Android手勢識別GestureDetector詳解
一、概述
當用戶觸控式螢幕幕的時候,會產生許多手勢,例如down,up,scroll,filing等等。
一般情況下,我們知道View類有個View.OnTouchListener內部介面,通過重寫他的onTouch(View v, MotionEvent event)方法,我們可以處理一些touch事件,但是這個方法太過簡單,如果需要處理一些複雜的手勢,用這個介面就會很麻煩(因為我們要自己根據使用者觸控的軌跡去判斷是什麼手勢)。
Android sdk給我們提供了GestureDetector(Gesture:手勢Detector:識別)類,通過這個類我們可以識別很多的手勢,主要是通過他的onTouchEvent(event)方法完成了不同手勢的識別。雖然他能識別手勢,但是不同的手勢要怎麼處理,應該是提供給程式設計師實現的。
GestureDetector這個類對外提供了兩個介面和一個外部類
介面:OnGestureListener,OnDoubleTapListener
內部類:SimpleOnGestureListener
這個外部類,其實是兩個介面中所有函式的整合,它包含了這兩個接口裡所有必須要實現的函式而且都已經重寫,但所有方法體都是空的;不同點在於:該類是static class,程式設計師可以在外部繼承這個類,重寫裡面的手勢處理方法。
下面我們先看OnGestureListener介面;
二、GestureDetector.OnGestureListener---介面
1、基本講解
如果我們寫一個類並implements OnGestureListener,會提示有幾個必須重寫的函式,加上之後是這個樣子的:
- privateclass gesturelistener implements GestureDetector.OnGestureListener{
- publicboolean onDown(MotionEvent e) {
- // TODO Auto-generated method stub
- returnfalse;
- }
- publicvoid onShowPress(MotionEvent e) {
- // TODO Auto-generated method stub
- }
- publicboolean onSingleTapUp(MotionEvent e) {
- // TODO Auto-generated method stub
- returnfalse;
- }
- publicboolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- // TODO Auto-generated method stub
- returnfalse;
- }
- publicvoid onLongPress(MotionEvent e) {
- // TODO Auto-generated method stub
- }
- publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- // TODO Auto-generated method stub
- returnfalse;
- }
- }
OnDown(MotionEvent e):使用者按下螢幕就會觸發;
onShowPress(MotionEvent e):如果是按下的時間超過瞬間,而且在按下的時候沒有鬆開或者是拖動的,那麼onShowPress就會執行,具體這個瞬間是多久,我也不清楚呃……
onLongPress(MotionEvent e):長按觸控式螢幕,超過一定時長,就會觸發這個事件
觸發順序:
onDown->onShowPress->onLongPress
onSingleTapUp(MotionEvent e):從名子也可以看出,一次單獨的輕擊擡起操作,也就是輕擊一下螢幕,立刻擡起來,才會有這個觸發,當然,如果除了Down以外還有其它操作,那就不再算是Single操作了,所以也就不會觸發這個事件
觸發順序:
點選一下非常快的(不滑動)Touchup:
onDown->onSingleTapUp->onSingleTapConfirmed
點選一下稍微慢點的(不滑動)Touchup:
onDown->onShowPress->onSingleTapUp->onSingleTapConfirmed
onFling(MotionEvent e1, MotionEvent e2, float velocityX,float velocityY) :滑屏,使用者按下觸控式螢幕、快速移動後鬆開,由1個MotionEvent ACTION_DOWN, 多個ACTION_MOVE, 1個ACTION_UP觸發
引數解釋:
e1:第1個ACTION_DOWN MotionEvent
e2:最後一個ACTION_MOVE MotionEvent
velocityX:X軸上的移動速度,畫素/秒
velocityY:Y軸上的移動速度,畫素/秒
onScroll(MotionEvent e1, MotionEvent e2,float distanceX, float distanceY):在螢幕上拖動事件。無論是用手拖動view,或者是以拋的動作滾動,都會多次觸發,這個方法 在ACTION_MOVE動作發生時就會觸發
滑屏:手指觸動屏幕後,稍微滑動後立即鬆開
onDown-----》onScroll----》onScroll----》onScroll----》………----->onFling
拖動
onDown------》onScroll----》onScroll------》onFiling
可見,無論是滑屏,還是拖動,影響的只是中間OnScroll觸發的數量多少而已,最終都會觸發onFling事件!
2、例項
要使用GestureDetector,有三步要走:1、建立OnGestureListener監聽函式:
可以使用構造例項:
- GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener(){
- };
- privateclass gestureListener implements GestureDetector.OnGestureListener{
- }
建構函式有下面三個,根據需要選擇:
- GestureDetector gestureDetector=new GestureDetector(GestureDetector.OnGestureListener listener);
- GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.OnGestureListener listener);
- GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener);
- publicboolean onTouch(View v, MotionEvent event) {
- return mGestureDetector.onTouchEvent(event);
- }
4、控制元件繫結
- TextView tv = (TextView)findViewById(R.id.tv);
- tv.setOnTouchListener(this);
首先,在主佈局頁面新增一個textView,並將其放大到整屏,方便在其上的手勢識別,程式碼為:
- <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"
- tools:context="com.example.gesturedetectorinterface.MainActivity" >
- <TextView
- android:id="@+id/tv"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_margin="50dip"
- android:background="#ff00ff"
- android:text="@string/hello_world" />
- </RelativeLayout>
- publicclass MainActivity extends Activity implements OnTouchListener{
- private GestureDetector mGestureDetector;
- @Override
- protectedvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- mGestureDetector = new GestureDetector(new gestureListener()); //使用派生自OnGestureListener
- TextView tv = (TextView)findViewById(R.id.tv);
- tv.setOnTouchListener(this);
- tv.setFocusable(true);
- tv.setClickable(true);
- tv.setLongClickable(true);
- }
- /*
- * 在onTouch()方法中,我們呼叫GestureDetector的onTouchEvent()方法,將捕捉到的MotionEvent交給GestureDetector
- * 來分析是否有合適的callback函式來處理使用者的手勢
- */
- publicboolean onTouch(View v, MotionEvent event) {
- return mGestureDetector.onTouchEvent(event);
- }
- privateclass gestureListener implements GestureDetector.OnGestureListener{
- // 使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發
- publicboolean onDown(MotionEvent e) {
- Log.i("MyGesture", "onDown");
- Toast.makeText(MainActivity.this, "onDown", Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- /*
- * 使用者輕觸觸控式螢幕,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發
- * 注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態
- *
- * 而onDown也是由一個MotionEventACTION_DOWN觸發的,但是他沒有任何限制,
- * 也就是說當用戶點選的時候,首先MotionEventACTION_DOWN,onDown就會執行,
- * 如果在按下的瞬間沒有鬆開或者是拖動的時候onShowPress就會執行,如果是按下的時間超過瞬間
- * (這塊我也不太清楚瞬間的時間差是多少,一般情況下都會執行onShowPress),拖動了,就不執行onShowPress。
- */
- publicvoid onShowPress(MotionEvent e) {
- Log.i("MyGesture", "onShowPress");
- Toast.makeText(MainActivity.this, "onShowPress", Toast.LENGTH_SHORT).show();
- }
- // 使用者(輕觸觸控式螢幕後)鬆開,由一個1個MotionEvent ACTION_UP觸發
- ///輕擊一下螢幕,立刻擡起來,才會有這個觸發
- //從名子也可以看出,一次單獨的輕擊擡起操作,當然,如果除了Down以外還有其它操作,那就不再算是Single操作了,所以這個事件 就不再響應
- publicboolean onSingleTapUp(MotionEvent e) {
- Log.i("MyGesture", "onSingleTapUp");