Android: How to rotate a view with one finger

2019-07-06 08:59发布

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.

2条回答
Luminary・发光体
2楼-- · 2019-07-06 09:26

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;
}
查看更多
兄弟一词,经得起流年.
3楼-- · 2019-07-06 09:35
        @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;
        }
    };
查看更多
登录 后发表回答