使用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()。然后就是每次按下的时候需要设置下当前图片的矩阵值,使在移动的时候在此基础上进行移动.其它的就没有太难的地方,在草稿纸上画画就应该出来了
运行结果: