Android中手勢識別GestureDetector分析

在Android系統中,每一次手勢交互都會依照以下順序執行。

1. 接觸接觸屏一剎那,觸發一個MotionEvent事件。 

2. 該事件被OnTouchListener監聽,在其onTouch()方法裏獲得該MotionEvent對象。 

3. 通過GestureDetector(手勢識別器)轉發次MotionEvent對象


MotionEvent: 這個類用於封裝手勢、觸摸筆、軌跡球等等的動作事件。其內部封裝了兩個重要的屬性X和Y,這兩個屬性分別用於記錄橫軸和縱軸的座標。
GestureDetector: 識別各種手勢,它提供了OnGestureListener和OnDoubleTapListener兩個接口,以及一個內部類SimpleOnGestureListener。
手勢交互的監聽接口,其中提供了多個抽象方法,並根據GestureDetector的手勢識別結果調用相對應的方法。

代碼說明:

佈局:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/a" />

</RelativeLayout>

實現OnGestureListener接口:

package com.example.gesturedetectortest;

import android.os.Bundle;
import android.util.Log;
import android.app.Activity;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
// OnGestureListener: 這是一個手勢交互的監聽接口,
//其中提供了多個抽象方法,並根據GestureDetector的手勢識別結果調用相對應的方法。
public class MainActivity extends Activity  implements OnGestureListener,OnTouchListener{
	public static final String TAG=MainActivity.class.getSimpleName();
	private ImageView iv;
	private GestureDetector detector;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		iv=(ImageView)findViewById(R.id.iv);
		detector=new GestureDetector(this, this);
		iv.setOnTouchListener(this);
	}

	//在onTouchEvent()方法中,我們調用GestureDetector的onTouchEvent()方法,
	//將捕捉到的MotionEvent交給GestureDetector來分析是否有合適的callback函數來處理用戶的手勢  
	//	@Override
	//	public boolean onTouchEvent(MotionEvent event) {
	//		// TODO Auto-generated method stub
	//		return this.detector.onTouchEvent(event);
	//	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		return this.detector.onTouchEvent(event);
	}
	//剛剛手指接觸到觸摸屏的那一剎那,由1個MotionEvent ACTION_DOWN觸發 
	@Override
	public boolean onDown(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onDown   y=" + e.getY());  	
		return true;
	}
	// 手指按在觸摸屏上,它的時間範圍在按下起效,在長按之前,
	//由一個1個MotionEvent ACTION_DOWN觸發  
	//注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態  
	@Override
	public void onShowPress(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onShowPress");
	}
	//手指離開觸摸屏的那一剎那
	//由一個1個MotionEvent ACTION_UP觸發  
	@Override
	public boolean onSingleTapUp(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onSingleTapUp    y=" + e.getY());
		return true;
	}
	//手指按下且在屏上滑動
	//由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE觸發
	@Override
	public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onScroll:distanceX = " + distanceX + " distanceY = " + distanceY);
		return true;
	}
	//手指長按觸屏幕,並且沒有鬆開
	//由多個MotionEvent ACTION_DOWN觸發
	@Override
	public void onLongPress(MotionEvent e) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onLongPress");
	}
	//手指在觸摸屏上迅速移動,並鬆開的動作
	//由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE, 1個ACTION_UP觸發 
	//e1:第1個ACTION_DOWN MotionEvent ,e2:最後一個ACTION_MOVE MotionEven
	//velocityX:X軸上的移動速度,像素/秒  ,velocityY:Y軸上的移動速度,像素/秒   

	@Override
	public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
		// TODO Auto-generated method stub
		Log.i(TAG, "onFling");
		if(e1.getX()-e2.getX()>100&&Math.abs(velocityX)>200){
			Log.i(TAG, "onFling   向左滑動");
			return true;
		}else if(e1.getX()-e2.getX()<-100&&Math.abs(velocityX)>200){
			Log.i(TAG, "onFling   向右滑動");
			return true;
		}else if(e1.getY()-e2.getY()>10&&Math.abs(velocityY)>50){
			Log.i(TAG, "onFling   向上滑動  上位移="+(e1.getY()-e2.getY()));
			return true;
		}else if(e1.getY()-e2.getY()<-10&&Math.abs(velocityY)>50){
			Log.i(TAG, "onFling   向下滑動    下位移"+(e1.getY()-e2.getY()));
			return true;
		}
		return false;
	}


	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
}

onFling方法中可以通過其參數進行一些條件設置,如左右上下滑動的條件。

Activity中的onTouchEvent方法和OnTouchListener中的onTouch方法,都可以實現調用GestureDetector的onTouchEvent()方法,將捕捉到的MotionEvent交給GestureDetector來分析是否有合適的callback函數來處理用戶的手勢,兩個直接的區別:查看http://www.xuebuyuan.com/1588148.html。

執行不同手勢時,logcat顯示:


SimpleOnGestureListener是一個抽象類,需要繼承,可選擇性的繼承自己所需的方法。

下面這個測試,來自網絡,其實和OnGestureListener比較多了幾個方法。

package com.example.gesturedetectortest;

import android.app.Activity;
import android.os.Bundle;
import android.os.storage.OnObbStateChangeListener;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;

public class SimpleOnGestureActivity extends Activity implements OnTouchListener{
	public static final String TAG=SimpleOnGestureActivity.class.getSimpleName();
	private GestureDetector detector;
	private ImageView iv;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_gestrue);
		iv=(ImageView)findViewById(R.id.iv);
		detector=new GestureDetector(this, new MySimpleGesture());
		iv.setOnTouchListener(this);
	}
	@Override
	public boolean onTouch(View v, MotionEvent event) {
		// TODO Auto-generated method stub
		return this.detector.onTouchEvent(event);

	}
	private class MySimpleGesture extends SimpleOnGestureListener{
		// 雙擊的第二下Touch down時觸發    
		public boolean onDoubleTap(MotionEvent e) {   
			Log.i(TAG, "onDoubleTap");   
			return super.onDoubleTap(e);   
		}   

		// 雙擊的第二下Touch down和up都會觸發,可用e.getAction()區分   
		public boolean onDoubleTapEvent(MotionEvent e) {   
			Log.i(TAG, "onDoubleTapEvent");   
			return super.onDoubleTapEvent(e);   
		}   

		// Touch down時觸發    
		public boolean onDown(MotionEvent e) {   
			Log.i(TAG, "onDown");   
			return super.onDown(e);   
		}   

		// Touch了滑動一點距離後,up時觸發   
		public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {   
			Log.i(TAG, "onFling");   
			return super.onFling(e1, e2, velocityX, velocityY);   
		}   

		// Touch了不移動一直Touch down時觸發   
		public void onLongPress(MotionEvent e) {   
			Log.i(TAG, "onLongPress");   
			super.onLongPress(e);   
		}   

		// Touch了滑動時觸發   
		public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {   
			Log.i(TAG, "onScroll");   
			return super.onScroll(e1, e2, distanceX, distanceY);   
		}   

		/*  
		 * Touch了還沒有滑動時觸發  
		 * (1)onDown只要Touch Down一定立刻觸發  
		 * (2)Touch Down後過一會沒有滑動先觸發onShowPress再觸發onLongPress  
		 * So: Touch Down後一直不滑動,onDown -> onShowPress -> onLongPress這個順序觸發。  
		 */  
		public void onShowPress(MotionEvent e) {   
			Log.i(TAG, "onShowPress");   
			super.onShowPress(e);   
		}   
		/*  
		 * 兩個函數都是在Touch Down後又沒有滑動(onScroll),又沒有長按(onLongPress),然後Touch Up時觸發  
		 * 點擊一下非常快的(不滑動)Touch Up: onDown->onSingleTapUp->onSingleTapConfirmed  
		 * 點擊一下稍微慢點的(不滑動)Touch Up: onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed   
		 */    
		public boolean onSingleTapConfirmed(MotionEvent e) {   
			Log.i(TAG, "onSingleTapConfirmed");   
			return super.onSingleTapConfirmed(e);   
		}   
		public boolean onSingleTapUp(MotionEvent e) {   
			Log.i(TAG, "onSingleTapUp");   
			return super.onSingleTapUp(e);   
		}   

	}
}


一些關於手勢的優秀的開源框架:http://jcodecraeer.com/plus/list.php?tid=31&codecategory=16500

示例代碼下載


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章