【问题标题】:Rotate canvas around the center of the screen whil also allowing translate围绕屏幕中心旋转画布,同时允许翻译
【发布时间】:2017-04-16 16:24:12
【问题描述】:

我正在使用 canvas.drawPath 绘制一个复杂的形状。这些 drawPath 方法的结果就像一张比屏幕大的地图。我希望用户执行以下操作:用一根手指移动地图。或者用两根手指围绕屏幕中心旋转它。基本上它的行为应该与谷歌地图完全一样,只是没有缩放。到目前为止,我能够获得所需的运动和旋转:

private void handleTouch(MotionEvent event)
{
    switch(event.getAction() & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_POINTER_DOWN:
        {
            rotate=true;
            move=false;
            a=Math.toDegrees(-Math.atan2(event.getX(0)-event.getX(1),event.getY(0)-event.getY(1)));
            if(a>360)a=a-360;
            if(a<-360)a=a+360;
            da=a-angle;
            if(da>360)da=da-360;
            if(da<-360)da=da+360;

        }
        break;
        case MotionEvent.ACTION_POINTER_UP:
        {
            rotate=false;
            move=false;
            x = (int)event.getX();
            y = (int)event.getY();
            dx = x - translate.x;
            dy = y - translate.y;
        }
        break;
        case MotionEvent.ACTION_DOWN:
        {
            move=true;
            x = (int)event.getX();
            y = (int)event.getY();
            dx = x - translate.x;
            dy = y - translate.y;
        }
        break;
        case MotionEvent.ACTION_MOVE:
        {
            if(rotate && event.getPointerCount()==2)
            {
                angle=Math.toDegrees((-Math.atan2(event.getX(0)-event.getX(1),event.getY(0)-event.getY(1))))-da;
                if(angle>360)angle=angle-360;
                if(angle<-360)angle=angle+360;
                vmap.invalidate();

            }
            else if(move==true)
            {
                translate.set((int)event.getX() - dx,(int)event.getY() - dy);
                //trans.setTranslate(translate.x,translate.y);

                vmap.invalidate();

            }

        }
        break;
        case MotionEvent.ACTION_UP:
        {
            //your stuff
        }
        break;

    }

问题在于正确地将它们应用在一起。如果我先平移然后围绕地图的中心坐标旋转,我可以轻松地围绕自己的中心旋转。但是,如果我尝试围绕屏幕中心旋转,事情就会变得复杂。假设我将画布向左移动 20 像素,然后将其旋转 30 度,然后向下移动 50 像素,然后再将其旋转 50 度。如果我尝试在第二次旋转期间将两个角度相加,我现在将围绕不同的坐标旋转,这意味着一旦我进行新的旋转,地图就会突然跳跃。

我研究过使用矩阵,但到目前为止没有帮助。

【问题讨论】:

    标签: android graphics rotation


    【解决方案1】:

    看看Matrix 类。它允许您以多种方式转换 ImageView。对于这个问题,我创建了一个包含成员的测试项目:

    ImageView imageView;
    Matrix imageMatrix = new Matrix();
    PointF screenCenter = new PointF();
    

    然后,在 onCreate() 中:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    
        DisplayMetrics metrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(metrics);
        screenCenter.x = metrics.widthPixels/2;
        screenCenter.y = metrics.heightPixels/2;
    
        imageView = (ImageView) findViewById(R.id.image);
        imageView.setScaleType(ImageView.ScaleType.MATRIX);
        imageMatrix.set(imageView.getImageMatrix());
    }
    

    screenCenter 对象现在包含屏幕中心的坐标,稍后会用到。 imageView 缩放类型已设置为 MATRIX,并且 imageMatrix 已设置为我们更改缩放类型时应用于视图的起始矩阵。

    现在,当您翻译时修改 imageMatrix,然后使用 setImageMatrix() 将新矩阵应用于视图:

    void translate(float x, float y) {
        imageMatrix.postTranslate(x, y);
        imageView.setImageMatrix(imageMatrix);
    }
    

    旋转的工作方式相同,但我们需要屏幕中心的坐标:

    void rotate(float angle) {
        imageMatrix.postRotate(angle, screenCenter.x, screenCenter.y);
        imageView.setImageMatrix(imageMatrix);
    }
    

    这适用于我的模拟器,无论如何翻译,翻译都会移动预期的方向,旋转总是围绕屏幕中心移动。不可否认,这是一个测试项目,看起来不太漂亮。

    OpenGL ES 包含在 Android 框架中,如果您走这条路,您可能会获得更好的图形性能。如果你这样做了,那么this answer 可能会有所帮助。

    【讨论】:

      猜你喜欢
      • 2013-08-04
      • 1970-01-01
      • 2022-10-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-02-14
      • 1970-01-01
      相关资源
      最近更新 更多