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,因此在按下时,我们必须标记单点与多点触控的区别。
附件中有采用枚举标识实现方式