使用Matrix实现图片移动和多点触摸

一、什么是Matrix?其实在Android中Matrix本质是一个3*3的矩阵
Matrix包括的图形处理包括以下4种。
-Translate 平移变换
-scale 缩放变换
-rotate 旋转变换
-skew 错切变换
前面三个比较容易理解,有点类似于动画中的变化,就不做介绍了,最后一个错切变化在数学上又称为Shear mapping或者Transvection,它是一种比较特殊的线性变换。错切变换的效果就是让所有点的X坐标(或者Y坐标)保持不变,让Y(X)坐标进行按比例发生平移,而且平移的大小和该点到X(Y)周的垂直距离成正比。错切变换的公式如下:

x = x0 + K1 * y0
y=K2*x0+y0

这篇博客用的技术只用到了Matrix的平移变换,其它的在后续会讲到。
OK,上代码。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000"
    tools:context="${relativePackage}.${activityClass}" >

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="matrix"
        android:src="@drawable/img" />

</RelativeLayout>

这个布局中只有一个ImageView,注意:要想让图片可以通过Matrix实现变化,必须加这行代码,否则不会起作用。

android:scaleType=”matrix”

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mIv = (ImageView) findViewById(R.id.iv);
        mStartPoint = new PointF(); 
        matrix = new Matrix(); 
        mCurrentMatrix = new Matrix();
        mIv.setOnTouchListener(new OnTouchListener() {

            @Override
            public boolean onTouch(View v, MotionEvent event) {
                switch (event.getActionMasked()) {
                case MotionEvent.ACTION_DOWN:
                    //将模式改为拖拽
                    mode = DRAG ;
                    //当手指按下的时候,记录一开始按下的位置
                    mCurrentMatrix.set(mIv.getImageMatrix());
                    mStartPoint.x = event.getX();
                    mStartPoint.y = event.getY() ;
                    break;
                case MotionEvent.ACTION_MOVE:
                    if(mode == DRAG){
                        //计算移动的距离
                        float dx = event.getX() - mStartPoint.x ;
                        float dy = event.getY() - mStartPoint.y;
                        //在没有移动的基础上开始移动
                        matrix.set(mCurrentMatrix);
                        matrix.set(mCurrentMatrix); 
                        //利用矩阵移动
                        matrix.postTranslate(dx, dy) ;
                    }else if(mode == ZOOM){
                        mMoveInstance = distance(event);
                        //计算缩放比例
                        float scale = mMoveInstance / mStartInstance ;
                        centerP = calculateCenter(event);
                        //基于上一次的放大倍数基础上进行缩放
                        matrix.set(mCurrentMatrix);
                        System.out.println("scale:" + scale );
                        matrix.postScale(scale, scale, centerP.x  , centerP.y ) ;
                    }

                    break;
                //在第二根手指按下的时候计算此时的距离
                case MotionEvent.ACTION_POINTER_DOWN:
                    mStartInstance = distance(event);
                    centerP = calculateCenter(event);
                    //记录当前的矩阵
                    mCurrentMatrix.set(mIv.getImageMatrix()); 
                    //将模式改为缩放
                    mode = ZOOM ;
                    break;
                case MotionEvent.ACTION_UP:
                case MotionEvent.ACTION_POINTER_UP:
                    mode = 0 ;
                    break;
                }
                mIv.setImageMatrix(matrix);
                return true;//将事件消费
            }
        });
    }

可能有些童鞋不太了解event.getActionMasked(),其实,我们点进去看源码知道点了

public final int getActionMasked() { 
 return nativeGetAction(mNativePtr) & ACTION_MASK; 
 }

而getAction()的源码如下:

public final int getAction() { 
 return nativeGetAction(mNativePtr); 
 }

ACTION_MASK到底是什么呢?

/** 
 * Bit mask of the parts of the action code that are the action itself. 
 */ 
 public static final int ACTION_MASK = 0xff;protected PointF calculateCenter(MotionEvent event) {
        float dx = event.getX(1) + event.getX(0);
        float dy = event.getY(1)+event.getY(0);
        return new PointF(dx / 2 ,dy / 2);
    }protected float distance(MotionEvent event) {
        float x = event.getX(1) - event.getX(0);
        float y = event.getY(1) - event.getY(0);
        return (float) Math.sqrt(x * x + y * y) ;
    }

由此可以看出getActionMasked()就相当于getAction()&&255,相当于将高位屏蔽掉了。总之,记住,要想实现多点触摸,就使用getActionMasked()。然后就是每次按下的时候需要设置下当前图片的矩阵值,使在移动的时候在此基础上进行移动.其它的就没有太难的地方,在草稿纸上画画就应该出来了

运行结果:

Android 开发 图片旋转 android matrix 旋转_多点触摸和图片查看