ImageView通過matrix實現手勢縮放
來自: http://www.jcodecraeer.com//a/anzhuokaifa/androidkaifa/2013/1023/1579.html
關于ImageView的手勢縮放,有很多種方法,絕大多數開源自定義縮放都是修改了ondraw函數來實現的。但是ImageView本身有scaleType屬性,通過設置android:scaleType="matrix" 可以用很少的代碼就實現縮放功能。縮放的優點是實現起來簡單,同時因為沒有反復調用ondraw函數,縮放過程中不會有閃爍現象。
MATRIX矩陣可以動態縮小放大圖片來顯示,縮小圖片:
//獲得Bitmap的高和寬 int bmpWidth=bmp.getWidth(); int bmpHeight=bmp.getHeight(); //設置縮小比例 double scale=0.8; //計算出這次要縮小的比例 scaleWidth=(float)(scaleWidth*scale); scaleHeight=(float)(scaleHeight*scale); //產生resize后的Bitmap對象 Matrix matrix=new Matrix(); matrix.postScale(scaleWidth, scaleHeight); Bitmap resizeBmp=Bitmap.createBitmap(bmp, 0, 0, bmpWidth, bmpHeight, matrix, true);
下面將一個自定義的實現了手勢縮放的ImageView代碼拷貝如下:
package com.jcodecraeer.stargallerry;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.PointF;
import android.util.AttributeSet;
import android.util.FloatMath;
import android.view.MotionEvent;
import android.widget.ImageView;
public class ImageTouchView extends ImageView {
private PointF startPoint = new PointF();
private Matrix matrix = new Matrix();
private Matrix currentMaritx = new Matrix();
private int mode = 0;//用于標記模式
private static final int DRAG = 1;//拖動
private static final int ZOOM = 2;//放大
private float startDis = 0;
private PointF midPoint;//中心點
/**
* 默認構造函數
* @param context
*/
public ImageTouchView(Context context){
super(context);
}
/**
* 該構造方法在靜態引入XML文件中是必須的
* @param context
* @param paramAttributeSet
*/
public ImageTouchView(Context context,AttributeSet paramAttributeSet){
super(context,paramAttributeSet);
}
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
mode = DRAG;
currentMaritx.set(this.getImageMatrix());//記錄ImageView當期的移動位置
startPoint.set(event.getX(),event.getY());//開始點
break;
case MotionEvent.ACTION_MOVE://移動事件
if (mode == DRAG) {//圖片拖動事件
float dx = event.getX() - startPoint.x;//x軸移動距離
float dy = event.getY() - startPoint.y;
matrix.set(currentMaritx);//在當前的位置基礎上移動
matrix.postTranslate(dx, dy);
} else if(mode == ZOOM){//圖片放大事件
float endDis = distance(event);//結束距離
if(endDis > 10f){
float scale = endDis / startDis;//放大倍數
//Log.v("scale=", String.valueOf(scale));
matrix.set(currentMaritx);
matrix.postScale(scale, scale, midPoint.x, midPoint.y);
}
}
break;
case MotionEvent.ACTION_UP:
mode = 0;
break;
//有手指離開屏幕,但屏幕還有觸點(手指)
case MotionEvent.ACTION_POINTER_UP:
mode = 0;
break;
//當屏幕上已經有觸點(手指),再有一個手指壓下屏幕
case MotionEvent.ACTION_POINTER_DOWN:
mode = ZOOM;
startDis = distance(event);
if(startDis > 10f){//避免手指上有兩個繭
midPoint = mid(event);
currentMaritx.set(this.getImageMatrix());//記錄當前的縮放倍數
}
break;
}
this.setImageMatrix(matrix);
return true;
}
/**
* 兩點之間的距離
* @param event
* @return
*/
private static 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);
}
/**
* 計算兩點之間中心點的距離
* @param event
* @return
*/
private static PointF mid(MotionEvent event){
float midx = event.getX(1) + event.getX(0);
float midy = event.getY(1) - event.getY(0);
return new PointF(midx/2, midy/2);
}
}
在xml中這樣使用自定義的ImageView:
<com.jcodecraeer.stargallerry.ImageTouchView
android:id="@+id/image"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="matrix"
/> 這里有個小細節, android:layout_width和android:layout_height這里都是="match_parent" ,如果我們換成wrap_content的話,你會發現圖片只能在一個很小的區間縮放。而match_parent則可以很隨意的在整個屏幕縮放。
但是match_parent導致了一個讓人意外的問題:
如果將imageView的寬度和高度都設置為填充整個父控件,然后scaleType設置成Matrix,則圖片不是居中顯示的,整個圖片靠上去了,這里我還沒有找出原因,不過在網上找出了解決的辦法:
“
先設置ImageView的ScaleType="CENTER"
要給控件添加拖動與放大縮水前。再把ScaleType設為:"Matric"
(即ImageView設置OnTouchListener前更改屬性即可)
”
其中“ImageView設置OnTouchListener前更改屬性”在我們這個例子中應替換為在caseMotionEvent.ACTION_MOVE://移動事件開始更改屬性。在代碼中更改ScaleType應該這樣做:
this.setScaleType(ImageView.ScaleType.MATRIX);
說到ScaleType,我們看看ImageView.ScaleType 值的意義和區別:
CENTER /center 按圖片的原來size居中顯示,當圖片長/寬超過View的長/寬,則截取圖片的居中部分顯示
CENTER_CROP / centerCrop 按比例擴大圖片的size居中顯示,使得圖片長(寬)等于或大于View的長(寬)
CENTER_INSIDE / centerInside 將圖片的內容完整居中顯示,通過按比例縮小或原來的size使得圖片長/寬等于或小于View的長/寬
FIT_CENTER / fitCenter 把圖片按比例擴大/縮小到View的寬度,居中顯示
FIT_END / fitEnd 把圖片按比例擴大/縮小到View的寬度,顯示在View的下部分位置
FIT_START / fitStart 把圖片按比例擴大/縮小到View的寬度,顯示在View的上部分位置
FIT_XY / fitXY 把圖片不按比例擴大/縮小到View的大小顯示
MATRIX / matrix 用矩陣來繪制