Android開發學習之ImageView手勢拖拽、縮放、旋轉

在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;
	}
}

四、 運行效果

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *