Android: How to rotate an element by touching it?

I try to turn the view pushed inward by touching it and moving my finger. I came up with several solutions, but none of them feel natural on the device.

Here is my first approach: depending on where the user touched the screen and in which direction the finger was moved, I change the rotational rotation, calculated more or less arbitrarily.

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;
}

This approach had several annoying side effects: sometimes the stretchable rotated until the finger moved, and the rotation was usually not as fast as the user's finger.

Therefore, I threw away this code and started with my second approach. I use trigonometry to calculate the actual rotation, which will be equivalent to the movement of the finger:

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);
}

, . - ? , , .

, , , . , ?

Edit:

Snailer. atan2, , :

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

, , . . 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) .

+4

Source: https://habr.com/ru/post/1774822/


All Articles