wuqingman 2014-11-26
Android多点触控 Matrix图片随意的放大缩小,拖动
一、新建一个项目AnroidImageDragAndZoom,并准备一张照片放在res/drawable-hdpi目录下,如下图所示:
二、设置应用的UI界面,在main.xml中设置:
三、MainActivity.java中实现具体的需求
package com.example.anroidimagedragandzoom; import android.app.Activity; import android.graphics.Matrix; import android.graphics.PointF; import android.os.Bundle; import android.util.FloatMath; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.widget.ImageView; /** * 枚举方式实现事件 * @author miaowei * */ public class MainActivityEnum extends Activity{ private enum Type{ /** * 记录是拖放照片模式还是放大缩小照片模式 */ MODE, /** * 拖放照片模式 */ MODE_DRAG, /** * 放大缩小照片模式 */ MODE_ZOOM } private ImageView imageView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); imageView = (ImageView)findViewById(R.id.imageView); imageView.setOnTouchListener(touchListener); } private class MainEventEnmu extends EventInfoBase<Enum<?>>{ @Override public void setEvent(Enum<?> event) { super.setEvent(event); } } private OnTouchListener touchListener = new OnTouchListener() { /** * 用于记录开始时候的坐标位置 */ private PointF startPoint = new PointF(); /** * 用于记录拖拉图片移动的坐标位置 */ private Matrix matrix = new Matrix(); /** * 用于记录图片要进行拖拉时候的坐标位置 */ private Matrix currentMatrix = new Matrix(); /** * 两个手指的开始距离 */ private float startDis; /** * 两个手指的中间点 */ private PointF midPointF; MainEventEnmu mainEventEnmu = new MainEventEnmu(); @Override public boolean onTouch(View v, MotionEvent event) { //通过与运算保留最后八位 MotionEvent.ACTION_MASK = 255 switch (event.getAction() & MotionEvent.ACTION_MASK) { //手指压下屏幕 case MotionEvent.ACTION_DOWN: mainEventEnmu.setEvent(Type.MODE_DRAG); //记录ImageView当前的移动位置 currentMatrix.set(imageView.getImageMatrix()); startPoint.set(event.getX(), event.getY()); break; //手指在屏幕上移动,改事件会被不断触发 case MotionEvent.ACTION_MOVE: //拖拉图片 if (mainEventEnmu.getEvent() == Type.MODE_DRAG) { //得到X轴的移动距离 float dx = event.getX() - startPoint.x; //得到Y轴的移动距离 float dy = event.getY() - startPoint.y; //在没有移动之前的位置上进行移动 matrix.set(currentMatrix); matrix.postTranslate(dx, dy); } //放大缩小图片 else if (mainEventEnmu.getEvent() == Type.MODE_ZOOM) { //结束距离 float endDis = distance(event); // 两个手指并拢在一起的时候像素大于10 if (endDis > 10f) { // 得到缩放倍数 float scale = endDis / startDis; matrix.set(currentMatrix); matrix.postScale(scale, scale,midPointF.x,midPointF.y); } } break; // 手指离开屏幕 case MotionEvent.ACTION_UP: //当触点离开屏幕,但是屏幕上还有触点(手指),多点 case MotionEvent.ACTION_POINTER_UP: mainEventEnmu.setEvent(Type.MODE); break; // 当屏幕上已经有触点(手指),再有一个触点压下屏幕,多点 case MotionEvent.ACTION_POINTER_DOWN: mainEventEnmu.setEvent(Type.MODE_ZOOM); /** 计算两个手指间的距离 */ startDis = distance(event); // 两个手指并拢在一起的时候像素大于10 if (startDis > 10f) { midPointF = mid(event); //记录当前ImageView的缩放倍数 currentMatrix.set(imageView.getImageMatrix()); } break; } imageView.setImageMatrix(matrix); return true; } }; /** * 计算两个手指间的距离 * @param event * @return */ private float distance(MotionEvent event){ float dx = event.getX(1) - event.getX(0); float dy = event.getY(1) - event.getY(0); //使用勾股定理返回两点神之间的距离 return FloatMath.sqrt(dx * dx + dy * dy); } /** * 计算两个手指间的中间点 * @return */ private PointF mid(MotionEvent evntEvent){ float midX = (evntEvent.getX(1) + evntEvent.getX(0)); float midY = (evntEvent.getY(1) + evntEvent.getY(0)); return new PointF(midX, midY); } }
Activity需要实现一个OnTouchListener的方法,来设置ImageView的侦听属性,该接口位于android.view.View.OnTouchListener。
实现onTouch(View view, MotionEvent event)的方法,就可以获取触屏的感应事件了。
在该事件中,有两个参数可以用来获取对触摸的控制,这两个参数分别为:MotionEvent.getAction()和MotionEvent.ACTION_MASK,前者用于对单点触控进行操作,后者用于对多点触控进行操作,相应地,我们可以通过Android Developers’ Reference看到,对于单点触控,我们由MotionEvent.getAction()可以得到以下几种事件:ACTION_DOWN、ACTION_UP,而对于多点触控,由MotionEvent.ACTION_MASK,我们可以得到:ACTION_POINTER_DOWN、ACTION_POINTER_UP,都是MotionEvent中的常量,可以直接调用。而有些常量则是单点和多点共用的,如:ACTION_MOVE,因此在按下时,我们必须标记单点与多点触控的区别。
附件中有采用枚举标识实现方式