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,因此在按下時,我們必須標記單點與多點觸控的區別。
附件中有采用枚舉標識實現方式