Android:如何通过触摸来旋转元素?

时间:2010-11-14 20:14:14

标签: android graphics touch

我正试图通过触摸并移动手指来旋转视图中的可绘制内容。我已经提出了几种解决方案,但没有一种解决方案在设备上感觉很自然。

这是我的第一种方法:根据用户触摸屏幕的位置以及手指移动的方向,我改变了可绘制的旋转,或多或少地随意计算。

private void updateRotation(float x, float y, float oldX, float oldY) {
    int width = getWidth();
    int height = getHeight();

    float centerX = width / 2;
    float centerY = height / 2;

    float xSpeed = rotationSpeed(x, oldX, width);
    float ySpeed = rotationSpeed(y, oldY, height); 

    if ((y < centerY && x > oldX)
        || (y > centerY && x < oldX))
        rotation += xSpeed;
    else if ((y < centerY && x < oldX)
             || (y > centerY && x > oldX))
        rotation -= xSpeed;

    if ((x > centerX && y > oldY)
        || (x < centerX && y < oldY))
        rotation += ySpeed;
    else if ((x > centerX && y < oldY)
             || (x < centerX && y > oldY))
        rotation -= ySpeed;
}

private static float rotationSpeed(float pos, float oldPos, float max) {
    return (Math.abs(pos - oldPos) * 180) / max;
}

这种方法有一些恼人的副作用:有时候画笔会在手指没有移动的情况下旋转,旋转速度通常不如用户的手指快。

因此我抛弃了这段代码并开始了我的第二种方法。我正在使用三角学来计算与手指运动相当的实际旋转:

private void updateRotation(float x, float y, float oldX, float oldY) {
    float centerX = getWidth() / 2;
    float centerY = getHeight() / 2;

    float a = distance(centerX, centerY, x, y);
    float b = distance(centerX, centerY, oldX, oldY);
    float c = distance(x, y, oldX, oldY);

    double r = Math.acos((Math.pow(a, 2) + Math.pow(b, 2) - Math.pow(c, 2))
                         / (2 * a * b));

    if ((oldY < centerY && x < oldX)
        || (oldY > centerY && x > oldX)
        || (oldX > centerX && y < oldY)
        || (oldX < centerX && y > oldY))
        r *= -1; 

    rotation += (int) Math.toDegrees(r);
}

private float distance(float x1, float y1, float x2, float y2) {
    return Math.abs(x1 - x2) + Math.abs(y1 - y2);
}

虽然这对我来说听起来像是正确的解决方案,但它也不能正常工作。手指运动有时会被忽略 - 计算能否过于昂贵?此外,旋转仍然比实际手指移动快一点。

理想情况下,如果我开始旋转绘图触摸特定点,则此点应始终保持在手指下方。你能告诉我如何实现这个目标吗?

修改

这是我对Snailer建议的采纳。我不得不将atan2方法的参数切换到正确的方向,现在效果很好:

private void updateRotation(float x, float y) {
    double r = Math.atan2(x - getWidth() / 2, getHeight() / 2 - y);
    rotation = (int) Math.toDegrees(r);
}

1 个答案:

答案 0 :(得分:4)

通过获取手指和屏幕中心创建的角度,可以轻松完成此操作。与上面第二个例子中的内容类似。在onTouchEvent发送getX()/getY()此方法:

    private double getDegreesFromTouchEvent(float x, float y){
        double delta_x = x - (Screen Width) /2;
        double delta_y = (Screen Height) /2 - y;
        double radians = Math.atan2(delta_y, delta_x);

        return Math.toDegrees(radians);
    }

然后当你绘制()时,你可以根据结果旋转画布。显然,您需要使用if (MotionEvent.getAction() == MotionEvent.ACTION_MOVE)来更新角度。