Android多点触控---Matrix图片随意的放大缩小,拖动

wuqingman 2014-11-26

 Android多点触控 Matrix图片随意的放大缩小,拖动

一、新建一个项目AnroidImageDragAndZoom,并准备一张照片放在res/drawable-hdpi目录下,如下图所示:


Android多点触控---Matrix图片随意的放大缩小,拖动
 

二、设置应用的UI界面,在main.xml中设置:


Android多点触控---Matrix图片随意的放大缩小,拖动
 

三、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,因此在按下时,我们必须标记单点与多点触控的区别。

附件中有采用枚举标识实现方式