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 用矩陣來繪制