1. 程式人生 > >Android開發學習之ImageView手勢拖拽、縮放、旋轉

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

       四、 執行效果


相關推薦

Android開發學習ImageView手勢旋轉

           在Android應用中,圖片隨手勢的拖拽、縮放、旋轉在很多場景中都會用到,今天我們要做的就是在ImageView的基礎上實現一個可以拖拽、縮放、轉轉的TouchView。              一、實現原理              OnTouc

Android 使用變形矩陣實現可以旋轉的影象

上篇博文介紹了變形矩陣的一些用法,所以這篇博文就結合變形矩陣來實現一個可以拖拽、縮放、旋轉的影象吧。 首先,我們就繼承ImageView來實現我們的自定義View。 程式碼如下: public class MyMatrixImg extends Ima

Android開發學習路--異步消息Handler,Message,Looper和AsyncTask初體驗

被調用 project 輸入 gettext npos article app sso 音樂播放 在簡易音樂播放器中。用了Handler。也沒有過多地去研究學習,這裏再學習下android下的異步消息處理機制。這裏用了Handler主要是在線程中不能更新UI

Android開發學習路--圖表實現(achartengine/MPAndroidChart)初體驗

bundle 喜歡 嵌入式linux Y軸 tid ren sca ref java代碼 ??已經有一段時間沒有更新博客了,在上周離開工作了4年的公司,從此不再安安穩穩地工作了。很多其它的是接受挑戰和實現自身價值的提高。離開了嵌入式linux,從此擁抱移

Android開發學習路-EventBus使用

轉載自: https://www.cnblogs.com/Fndroid/p/5910992.html EventBus是一個通過釋出、訂閱事件實現元件間訊息傳遞的工具。 它存在的目的,就是為了優化元件之間傳遞訊息的過程。傳統元件之間傳遞訊息的方法有使用廣播,回撥等,而這些方法使用都比較

Android開發學習路--Android Studio外掛開發

前言 因為使用了mvp和dagger,所以每次新的一個功能頁面都需要重新寫一堆東西,比如Activity, Fragment, Presenter,dagger等,而這些程式碼基本上都是大同小異,完全可以寫一個模板,然後生成,略微修改便可以完成我們需要的功能。

Android開發學習路--Drawable mutations

  時間過得很快,明天終於可以拿到房子了,交完這次房租,也可以成為房東了,看看部落格也好久沒有更新了,最近一直在整機器人,也沒有太多時間整理部落格。   今天下午和同事一起遇到了一個問題,就是明明沒有

Android開發學習路--RxAndroid簡單原理

  學習了RxAndroid,其實也就是RxJava了,但是還是不是非常清楚到底RxAndroid有什麼用呢?為什麼要使用RxAndroid呢?這篇文章講得不錯,RxJava的原理。但是這裡還是把整個過

Android開發學習路--Activity初體驗

    環境也搭建好了,android系統也基本瞭解了,那麼接下來就可以開始學習android開發了,相信這麼學下去肯定可以把android開發學習好的,再加上時而再溫故下linux下的知識,看看an

Android開發學習TypedArray類

     在學習Android的開發中,學習Gallery檢視顯示圖片的過程中,在設定圖片介面卡的時候,用到了此TypedArray型別,這次根據android SDK,一塊把此型別弄清楚!      android.content.res.TypedArray     

Android開發學習路--在Android應用中愉快地寫C/C++程式碼

1 前言 一直想在android層面寫c程序,然後java可以與c程序互動,以前在android原始碼中想玩就可以直接在init.rc中加上交叉編譯好的c程序就可以了,而在ide中,也就是ndk編譯後各種許可權問題就有點不得而知了。花了幾天時間研究實踐,也終於

Android開發學習路--Android Studio cmake編譯ffmpeg

  最新的android studio2.2引入了cmake可以很好地實現ndk的編寫。這裡使用最新的方式,對於以前的android下的ndk編譯什麼的可以參考之前的文章:Android開發學習之路–NDK、JNI之初體驗。 1.ffmpeg編譯  

Android開發學習路--資料持久化初體驗

    上班第一天,雖然工作上處於醬油模式,但是學習上依舊不能拉下,接著學習android開發吧,這裡學習資料持久化的 知識。     其實資料持久化就是資料可以儲存起來,一般我們儲存資料都是以檔案,或者資料庫的形式儲存的,android程式也有 檔案和資料庫的儲存,此外還

Android開發學習路--非同步訊息Handler,Message,Looper和AsyncTask初體驗

    在簡易音樂播放器中,用了Handler,也沒有過多地去研究學習,這裡再學習下android下的非同步訊息處理機制。這裡用了Handler主要是線上程中不能更新UI,而需要通過Handler才可以。關於非同步訊息處理有幾個概念。     1、Message:訊息,執行

Android開發學習基於ZBar實現微信掃一掃

          蟄伏半月有餘,一直在準備期末考試,期間抽空研究了一些Android的原始碼,現在我就把在這其中的一些收穫分享給大家。        今天想分享給大家的是二維碼掃描。說起二維碼,大家一定不會陌生,尤其是微信火了以後,在我們的生活中幾乎隨處都可以看到二維碼的

Android開發學習使用百度語音識別SDK實現語音識別(上)

        作為移動網際網路殺手級的互動方式,語音識別從問世以來就一直備受人們的關注,從IOS的Siri到國內的訊飛語音,語音識別技術在移動開發領域是最為充滿前景和希望的技術。Android作為一個移動作業系統,其本身就繼承了Google天生的搜尋基因,因此Androi

Android開發學習路--NDKJNI初體驗

    好久沒有更新部落格了,最近一直在看一個仿微信專案,然後看原始碼並自己實現下,相信經過這個專案可以讓自己瞭解一個專案中的程式碼以及種種需要注意的事項。不知不覺中部落格已經快要40w訪問量,而且排名也即將突破3000了,在此感謝朋友們的支援和認可。今天趁著有點時間就來完

Android開發學習卡片式佈局的簡單實現

             GoogleNow是Android4.1全新推出的一款應用,它可以全面瞭解你的使用習慣,併為你提供現在或者未來可能用到的各種資訊,GoogleNow提供的資訊關聯度較高,幾乎

Android開發學習路--UI基本佈局

    上一篇文章中主要介紹了ui的控制元件,這裡就學習下佈局吧。android的基本佈局在layout下主要如圖:     從上圖可以看出有FrameLayout(單幀佈局),LinearLayo

Android開發學習SQLite詳解一

一.SQLite的介紹 1.SQLite簡介  SQLite是一款輕型的資料庫,是遵守ACID的關聯式資料庫管理系統,它的設計目標是嵌入 式的,而且目前已經在很多嵌入式產品中使用了它,它佔用資源非常的低,在嵌入式裝置中,可能只需要幾百K的記憶體就夠了。它能夠支援 Windo