Android:如何用一只手指旋转视图

4

我需要旋转一个视图,其中包含一些按钮。随着手指的移动,视图应该沿着其子视图相应地旋转。

到目前为止,我已经实现了以下内容:

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

但是它不够流畅,因此无法实现。

谢谢。

2个回答

7

首先,不要使用动画,因为您想在手指移动时直接更改视图。

然后,在计算方面,将OnTouchListener附加到所需旋转的视图的父视图上会更容易,这样触摸事件的坐标不会被旋转本身修改。

如果您有一个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;
}

我尝试使用旋转,但应该旋转到什么程度?当我使用mCurrAngle时它变得混乱了。 - Pramod Ravikant
你能描述一下当前的行为吗? - Nicolas Dusart
当我顺时针移动时,它显示异常行为。它同时顺时针和逆时针移动。 - Pramod Ravikant
尝试在atan2中颠倒参数,因为角度应该是atan(y/x) -> Math.atan2(yc-y,x-xc)。 - Nicolas Dusart
我进行了测试,发现确实存在一种故障,会使视图迅速抖动,但它会跟随手指移动。我注意到如果只在ACTION_DOWN时计算xc和yc,则会有所改善。另外,我怀疑event.getX/Y也会随着视图旋转,因此它的旋转速度比手指慢。也许需要在使用它们之前先将x、y 转换一下。 - Nicolas Dusart
1
我通过创建一个父布局并将监听器附加到它上面来使其工作。代码更简单,没有故障 ;) - Nicolas Dusart

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接