在Android應用中,圖片隨手勢的拖拽、縮放、旋轉在很多場景中都會用到,今天我們要做的就是在ImageView的基礎上實現一個可以拖拽、縮放、轉轉的TouchView。
一、實現原理
OnTouch事件捕捉+Matrix矩陣變換
二、核心方法
拖拽:Matrix.postTranslate(DeltalX, DeltalY);
縮放:Matrix.postScale(mScale, mScale, mPoint.x, mPoint.y);
旋轉:Matrix.postRotate(Angle, mPoint.x, mPoint.y);
三、具體實現
package com.Android.TouchView; /* * Android多點觸控技術練習 * @Author:Robin * @Date:2013年12月29日 * @邊界處理暫時不知道怎麼寫啊 * 目前的問題有: * 手勢識別不是很順暢,經常出現該放縮時放縮不瞭的情況 * 由於沒有邊界判斷,程序可能會出現崩潰 */ import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PaintFlagsDrawFilter; import android.graphics.PointF; import android.util.DisplayMetrics; import android.util.FloatMath; import android.view.MotionEvent; import android.widget.ImageView; @SuppressLint({ "ViewConstructor", "FloatMath" }) public class MultiTouchView extends ImageView { //本地圖像資源 private int mDrawable; //圖像位圖 private Bitmap mBitmap; //屏幕寬度 private int ScreenWidth; //屏幕高度 private int ScreenHeight; //原始圖像矩陣 private Matrix mMatrix=new Matrix(); //過程圖像矩陣 private Matrix mSavedMatrix=new Matrix(); //結果圖像矩陣 private Matrix mResultMatrix=new Matrix(); //定義三種模式:None、Drag、Zoom public static final int Mode_None=0; public static final int Mode_Drag=1; public static final int Mode_Zoom=2; //當前操作模式 private int mMode=Mode_None; //當前坐標 private float mDownX,mDownY; //存儲兩點間的距離 private float mDistance=0f; //存儲旋轉角 @SuppressWarnings("unused") private float mAngle=0f; //存儲中點 private PointF mPoint; //最大縮放比例 //private float MaxScale=3f; //最小縮放比例 //private float MinScale=0.5f; public MultiTouchView(Activity mActivity ,int Drawable) { super(mActivity); //設置當前圖片資源 this.mDrawable=Drawable; //獲取Bitmap mBitmap=BitmapFactory.decodeResource(getResources(), mDrawable); DisplayMetrics dm=new DisplayMetrics(); mActivity.getWindowManager().getDefaultDisplay().getMetrics(dm); //獲取屏幕寬度和高度 ScreenWidth=dm.widthPixels; ScreenHeight=dm.heightPixels; mMatrix=new Matrix(); } @SuppressLint("DrawAllocation") @Override protected void onDraw(Canvas canvas) { //消除圖像鋸齒 canvas.setDrawFilter(new PaintFlagsDrawFilter(0,Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG)); canvas.save(); //繪制圖像 canvas.drawBitmap(mBitmap, mMatrix, null); canvas.restore(); } @Override public boolean onTouchEvent(MotionEvent Event) { switch(Event.getAction()) { //單點觸控處理 case MotionEvent.ACTION_DOWN: //設置當前操作模式為Drag mMode=Mode_Drag; //獲取當前坐標 mDownX=Event.getX(); mDownY=Event.getY(); mSavedMatrix.set(mMatrix); break; //多點觸控處理 case MotionEvent.ACTION_POINTER_DOWN: mMode=Mode_Zoom; //獲取兩點間距離 mDistance=getDistance(Event); //獲取旋轉角 mAngle=getAngle(Event); //獲取中點 mPoint=getMidPoint(Event); mSavedMatrix.set(mMatrix); break; case MotionEvent.ACTION_MOVE: //縮放處理 if(mMode==Mode_Zoom) { mResultMatrix.set(mSavedMatrix); //獲取縮放比率 float mScale=getDistance(Event)/mDistance; //獲取旋轉角,這裡可以不用 //float Angle=getAngle(Event)-mAngle; //以中點為中心,進行縮放 mResultMatrix.postScale(mScale, mScale, mPoint.x, mPoint.y); //以中點為中心,進行旋轉,這裡可以不用 //mResultMatrix.postRotate(Angle, mPoint.x, mPoint.y); mMatrix.set(mResultMatrix); invalidate(); }else if(mMode==Mode_Drag)//平移處理 { mResultMatrix.set(mSavedMatrix); //計算平移量 float DeltalX=Event.getX()-mDownX; float DeltalY=Event.getY()-mDownY; //平移 mResultMatrix.postTranslate(DeltalX, DeltalY); mMatrix.set(mResultMatrix); invalidate(); } break; case MotionEvent.ACTION_UP: //這裡要不要處理呢,如果需要,怎麼辦 case MotionEvent.ACTION_POINTER_UP: mMode = Mode_None; break; } return true; } //返回兩點間的距離 public float getDistance(MotionEvent Event) { //計算X的變化量 float DeltalX=Event.getX(0)-Event.getX(1); //計算Y的變化量 float DeltalY=Event.getY(0)-Event.getY(1); //計算距離 return FloatMath.sqrt(DeltalX*DeltalX+DeltalY*DeltalY); } //返回兩點的中點 @SuppressLint("FloatMath") public PointF getMidPoint(MotionEvent Event) { float X=Event.getX(0)+Event.getX(1); float Y=Event.getY(0)+Event.getY(1); return new PointF(X/2,Y/2); } //獲得旋轉角 public float getAngle(MotionEvent Event) { double DeltalX=Event.getX(0)-Event.getX(1); double DeltalY=Event.getY(0)-Event.getY(1); return (float)Math.atan2(DeltalX, DeltalY); } //邊界處理,暫時沒找到比較好的方法 public boolean CheckBounary() { return false; } //存儲當前圖片 public Bitmap SaveImage() { Bitmap mBitmap = Bitmap.createBitmap(ScreenWidth, ScreenHeight,Config.ARGB_8888); Canvas mCanvas = new Canvas(mBitmap); mCanvas.drawBitmap(mBitmap, mMatrix, null); mCanvas.save(Canvas.ALL_SAVE_FLAG); mCanvas.restore(); return mBitmap; } }
四、 運行效果