1. 程式人生 > >Android手勢識別GestureDetector詳解

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,會提示有幾個必須重寫的函式,加上之後是這個樣子的:

  1. privateclass gesturelistener implements GestureDetector.OnGestureListener{  
  2.     publicboolean onDown(MotionEvent e) {  
  3.         // TODO Auto-generated method stub
  4.         returnfalse;  
  5.     }  
  6.     publicvoid onShowPress(MotionEvent e) {  
  7.         // TODO Auto-generated method stub
  8.     }  
  9.     publicboolean onSingleTapUp(MotionEvent e) {  
  10.         // TODO Auto-generated method stub
  11.         returnfalse;  
  12.     }  
  13.     publicboolean onScroll(MotionEvent e1, MotionEvent e2,  
  14.             float distanceX, float distanceY) {  
  15.         // TODO Auto-generated method stub
  16.         returnfalse;  
  17.     }  
  18.     publicvoid onLongPress(MotionEvent e) {  
  19.         // TODO Auto-generated method stub
  20.     }  
  21.     publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  22.             float velocityY) {  
  23.         // TODO Auto-generated method stub
  24.         returnfalse;  
  25.     }  
  26. }  
可見,這裡總共重寫了六個函式,這些函式都在什麼情況下才會觸發呢,下面講一下:

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監聽函式:
可以使用構造例項:

  1. GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener(){  
  2.     };  
也可以構造類:
  1. privateclass gestureListener implements GestureDetector.OnGestureListener{  
  2. }  
2、建立GestureDetector例項mGestureDetector:

建構函式有下面三個,根據需要選擇:

  1. GestureDetector gestureDetector=new GestureDetector(GestureDetector.OnGestureListener listener);  
  2. GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.OnGestureListener listener);  
  3. GestureDetector gestureDetector=new GestureDetector(Context context,GestureDetector.SimpleOnGestureListener listener);  
3、onTouch(View v, MotionEvent event)中攔截:
  1. publicboolean onTouch(View v, MotionEvent event) {  
  2.     return mGestureDetector.onTouchEvent(event);     
  3. }  

4、控制元件繫結

  1. TextView tv = (TextView)findViewById(R.id.tv);  
  2. tv.setOnTouchListener(this);  
現在進入例項階段:

首先,在主佈局頁面新增一個textView,並將其放大到整屏,方便在其上的手勢識別,程式碼為:

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2.     xmlns:tools="http://schemas.android.com/tools"
  3.     android:layout_width="match_parent"
  4.     android:layout_height="match_parent"
  5.     tools:context="com.example.gesturedetectorinterface.MainActivity" >  
  6.     <TextView  
  7.         android:id="@+id/tv"
  8.         android:layout_width="fill_parent"
  9.         android:layout_height="fill_parent"
  10.         android:layout_margin="50dip"
  11.         android:background="#ff00ff"
  12.         android:text="@string/hello_world" />  
  13. </RelativeLayout>  
然後在JAVA程式碼中,依據上面的三步走原則,寫出程式碼,並在所有的手勢下新增上Toast提示並寫上Log
  1. publicclass MainActivity extends Activity implements OnTouchListener{  
  2.     private GestureDetector mGestureDetector;     
  3.     @Override
  4.     protectedvoid onCreate(Bundle savedInstanceState) {  
  5.         super.onCreate(savedInstanceState);  
  6.         setContentView(R.layout.activity_main);  
  7.       mGestureDetector = new GestureDetector(new gestureListener()); //使用派生自OnGestureListener
  8.       TextView tv = (TextView)findViewById(R.id.tv);  
  9.       tv.setOnTouchListener(this);  
  10.       tv.setFocusable(true);     
  11.       tv.setClickable(true);     
  12.       tv.setLongClickable(true);   
  13.     }  
  14.     /*  
  15.      * 在onTouch()方法中,我們呼叫GestureDetector的onTouchEvent()方法,將捕捉到的MotionEvent交給GestureDetector  
  16.      * 來分析是否有合適的callback函式來處理使用者的手勢  
  17.      */
  18.     publicboolean onTouch(View v, MotionEvent event) {  
  19.         return mGestureDetector.onTouchEvent(event);     
  20.     }  
  21.     privateclass gestureListener implements GestureDetector.OnGestureListener{  
  22.         // 使用者輕觸觸控式螢幕,由1個MotionEvent ACTION_DOWN觸發   
  23.         publicboolean onDown(MotionEvent e) {  
  24.             Log.i("MyGesture""onDown");     
  25.             Toast.makeText(MainActivity.this"onDown", Toast.LENGTH_SHORT).show();     
  26.             returnfalse;  
  27.         }  
  28.         /*   
  29.          * 使用者輕觸觸控式螢幕,尚未鬆開或拖動,由一個1個MotionEvent ACTION_DOWN觸發   
  30.          * 注意和onDown()的區別,強調的是沒有鬆開或者拖動的狀態   
  31.          *  
  32.          * 而onDown也是由一個MotionEventACTION_DOWN觸發的,但是他沒有任何限制, 
  33.          * 也就是說當用戶點選的時候,首先MotionEventACTION_DOWN,onDown就會執行, 
  34.          * 如果在按下的瞬間沒有鬆開或者是拖動的時候onShowPress就會執行,如果是按下的時間超過瞬間 
  35.          * (這塊我也不太清楚瞬間的時間差是多少,一般情況下都會執行onShowPress),拖動了,就不執行onShowPress。 
  36.          */
  37.         publicvoid onShowPress(MotionEvent e) {  
  38.             Log.i("MyGesture""onShowPress");     
  39.             Toast.makeText(MainActivity.this"onShowPress", Toast.LENGTH_SHORT).show();     
  40.         }  
  41.         // 使用者(輕觸觸控式螢幕後)鬆開,由一個1個MotionEvent ACTION_UP觸發   
  42.         ///輕擊一下螢幕,立刻擡起來,才會有這個觸發
  43.         //從名子也可以看出,一次單獨的輕擊擡起操作,當然,如果除了Down以外還有其它操作,那就不再算是Single操作了,所以這個事件 就不再響應
  44.         publicboolean onSingleTapUp(MotionEvent e) {  
  45.             Log.i("MyGesture""onSingleTapUp");     
  46.