4

I need to rotate a view which have some buttons. With the finger movement, view should also rotate along with it's child views accordingly.

Till now I have implemented this:

private RelativeLayout mCircle;
private double mCurrAngle = 0;
private double mPrevAngle = 0;
int i = 0;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mCircle = (RelativeLayout) findViewById(R.id.circle);
    mCircle.setOnTouchListener(this); // Your activity should implement
                                        // OnTouchListener
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    final float xc = mCircle.getWidth() / 2;
    final float yc = mCircle.getHeight() / 2;

    final float x = event.getX();
    final float y = event.getY();

    switch (event.getAction()) {
    case MotionEvent.ACTION_DOWN: {
        mCircle.clearAnimation();
        mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
        break;
    }
    case MotionEvent.ACTION_MOVE: {
        mPrevAngle = mCurrAngle;
        mCurrAngle = Math.toDegrees(Math.atan2(x - xc, yc - y));
        mCircle.setRotation((float) (mPrevAngle - mCurrAngle));         

        animate(mPrevAngle, mCurrAngle, 0);
        break;
    }
    case MotionEvent.ACTION_UP: {
        mPrevAngle = mCurrAngle = 0;
        break;
    }
    }

    return true;
}

private void animate(double fromDegrees, double toDegrees,
        long durationMillis) {
    final RotateAnimation rotate = new RotateAnimation((float) fromDegrees,
            (float) toDegrees, RotateAnimation.RELATIVE_TO_SELF, 0.5f,
            RotateAnimation.RELATIVE_TO_SELF, 0.5f);
    rotate.setDuration(durationMillis);
    rotate.setFillEnabled(true);
    rotate.setFillAfter(true);
    mCircle.startAnimation(rotate);
}

But it is not smooth and thus can't be implemented.

Thanks.

Pramod Ravikant
  • 1,039
  • 2
  • 11
  • 28

2 Answers2

7

First, do not use animation, as you want to directly change the view as the finger moves.

Then, for the computations, it is a lot easier to attach the OnTouchListener to a parent view of the view you want to rotate, so that the coordinate of your touch event is not modified by the rotation itself.

Here is the code if you have a parent view with id "@+id/root":

private RelativeLayout mRoot;
private RelativeLayout mCircle;
int i = 0;
float viewRotation;
double fingerRotation;
double newFingerRotation;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mRoot = (RelativeLayout)findViewById(R.id.root);
     mCircle = (RelativeLayout) findViewById(R.id.circle);
     mRoot.setOnTouchListener(this);
}

@Override
public boolean onTouch(View v, MotionEvent event) {

    final float x = event.getX();
    final float y = event.getY();

    final float xc = mRoot.getWidth()/2;
    final float yc = mRoot.getHeight()/2;

    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            viewRotation = mCircle.getRotation();
            fingerRotation = Math.toDegrees(Math.atan2(x - xc, yc - y));
            break;
        case MotionEvent.ACTION_MOVE:
            newFingerRotation = Math.toDegrees(Math.atan2(x - xc, yc - y));
            mCircle.setRotation((float)(viewRotation + newFingerRotation - fingerRotation));
            break;
        case MotionEvent.ACTION_UP:
            fingerRotation = newFingerRotation = 0.0f;
            break;
    }

    return true;
}
Nicolas Dusart
  • 1,867
  • 18
  • 26
  • I tried using rotation but to what degree should I rotate? It gets messed up when I use `mCurrAngle` – Pramod Ravikant Dec 24 '13 at 09:50
  • Could you describe the current behaviour ? – Nicolas Dusart Dec 24 '13 at 10:49
  • When I am moving clockwise, it is showing abnormal behavior. It is moving clockwise and anticlockwise simultaneously. – Pramod Ravikant Dec 24 '13 at 10:54
  • Try reversing the arguments in atan2, as the angle should be atan(y/x) -> Math.atan2(yc-y,x-xc) – Nicolas Dusart Dec 24 '13 at 11:06
  • I tested it, there is indeed sort of a glitch that makes the view to shiver quickly but it follows the finger. I noticed a improve if you only compute xc and yc for the ACTION_DOWN. And also, I suspect the event.getX/Y to rotate with the views, so that it turns more slowly than your finger. Perhaps need to turn the x,y also before using them. – Nicolas Dusart Dec 24 '13 at 11:48
  • 1
    I managed to get it working by creating a parent layout and attach the listener to it instead. Much easier code, and glitch-free ;) – Nicolas Dusart Dec 24 '13 at 13:34
0
        @Override
        public boolean onTouch(View view, MotionEvent event) {  

             switch (action) {
                    case MotionEvent.ACTION_UP:
                        break;
                    case MotionEvent.ACTION_DOWN:

                        rotateX = event.getRawX();
                        rotateY = event.getRawY();

                        centerX = view.getX() + ((View) getParent()).getX() + (float) view.getWidth() / 2;

                        centerY = view.getY() + statusBarHeight + (float) view.getHeight() / 2;

                        break;

                    case MotionEvent.ACTION_MOVE:

                        newRotateX = event.getRawX();
                        newRotateY = event.getRawY();

                        double angle = Math.atan2(event.getRawY() - centerY, event.getRawX() - centerX) * 180 / Math.PI;

                        view.setRotation((float) angle - 45);

                        rotateX = newRotateX;
                        rotateY = newRotateY;
                }
            }

            return true;
        }
    };
joseRo
  • 1,337
  • 3
  • 18
  • 35