1. 程式人生 > >Android 手勢識別(單擊 雙擊 擡起 短按 長按 滾動 滑動)

Android 手勢識別(單擊 雙擊 擡起 短按 長按 滾動 滑動)

對於觸控式螢幕,其原生的訊息無非按下、擡起、移動這幾種,我們只需要簡單過載onTouch或者設定觸控偵聽器setOnTouchListener即可進行處理。不過,為了提高我們的APP的使用者體驗,有時候我們需要識別使用者的手勢,Android給我們提供的手勢識別工具GestureDetector就可以幫上大忙了。

  • 基礎

GestureDetector的工作原理是,當我們接收到使用者觸控訊息時,將這個訊息交給GestureDetector去加工,我們通過設定偵聽器獲得GestureDetector處理後的手勢。

GestureDetector提供了兩個偵聽器介面,OnGestureListener處理單擊類訊息,OnDoubleTapListener處理雙擊類訊息。

OnGestureListener的介面有這幾個:

  1. // 單擊,觸控式螢幕按下時立刻觸發
  2. abstractboolean onDown(MotionEvent e);  
  3. // 擡起,手指離開觸控式螢幕時觸發(長按、滾動、滑動時,不會觸發這個手勢)
  4. abstractboolean onSingleTapUp(MotionEvent e);  
  5. // 短按,觸控式螢幕按下後片刻後擡起,會觸發這個手勢,如果迅速擡起則不會
  6. abstractvoid onShowPress(MotionEvent e);  
  7. // 長按,觸控式螢幕按下後既不擡起也不移動,過一段時間後觸發
  8. abstractvoid onLongPress(MotionEvent e);  
  9. // 滾動,觸控式螢幕按下後移動
  10. abstractboolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);  
  11. // 滑動,觸控式螢幕按下後快速移動並擡起,會先觸發滾動手勢,跟著觸發一個滑動手勢
  12. abstractboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);  

OnDoubleTapListener的介面有這幾個:

  1. // 雙擊,手指在觸控式螢幕上迅速點選第二下時觸發
  2. abstract
    boolean onDoubleTap(MotionEvent e);  
  3. // 雙擊的按下跟擡起各觸發一次
  4. abstractboolean onDoubleTapEvent(MotionEvent e);  
  5. // 單擊確認,即很快的按下並擡起,但並不連續點選第二下
  6. abstractboolean onSingleTapConfirmed(MotionEvent e);  


有時候我們並不需要處理上面所有手勢,方便起見,Android提供了另外一個類SimpleOnGestureListener實現瞭如上介面,我們只需要繼承SimpleOnGestureListener然後過載感興趣的手勢即可。

  • 應用

STEP 1: 建立手勢偵聽物件

  1. package noodies.blog.csdn.net;  
  2. import android.content.Context;  
  3. import android.view.MotionEvent;  
  4. import android.view.GestureDetector.SimpleOnGestureListener;  
  5. import android.widget.Toast;  
  6. publicclass MyGestureListener extends SimpleOnGestureListener {  
  7.     private Context mContext;  
  8.     MyGestureListener(Context context) {  
  9.         mContext = context;  
  10.     }  
  11.     @Override
  12.     publicboolean onDown(MotionEvent e) {  
  13.         Toast.makeText(mContext, "DOWN " + e.getAction(), Toast.LENGTH_SHORT).show();  
  14.         returnfalse;  
  15.     }  
  16.     @Override
  17.     publicvoid onShowPress(MotionEvent e) {  
  18.         Toast.makeText(mContext, "SHOW " + e.getAction(), Toast.LENGTH_SHORT).show();             
  19.     }  
  20.     @Override
  21.     publicboolean onSingleTapUp(MotionEvent e) {  
  22.         Toast.makeText(mContext, "SINGLE UP " + e.getAction(), Toast.LENGTH_SHORT).show();  
  23.         returnfalse;  
  24.     }  
  25.     @Override
  26.     publicboolean onScroll(MotionEvent e1, MotionEvent e2,  
  27.             float distanceX, float distanceY) {  
  28.         Toast.makeText(mContext, "SCROLL " + e2.getAction(), Toast.LENGTH_SHORT).show();  
  29.         returnfalse;  
  30.     }  
  31.     @Override
  32.     publicvoid onLongPress(MotionEvent e) {  
  33.         Toast.makeText(mContext, "LONG " + e.getAction(), Toast.LENGTH_SHORT).show();  
  34.     }  
  35.     @Override
  36.     publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,  
  37.             float velocityY) {  
  38.         Toast.makeText(mContext, "FLING " + e2.getAction(), Toast.LENGTH_SHORT).show();  
  39.         returnfalse;  
  40.     }  
  41.     @Override
  42.     publicboolean onDoubleTap(MotionEvent e) {  
  43.         Toast.makeText(mContext, "DOUBLE " + e.getAction(), Toast.LENGTH_SHORT).show();  
  44.         returnfalse;  
  45.     }  
  46.     @Override
  47.     publicboolean onDoubleTapEvent(MotionEvent e) {  
  48.         Toast.makeText(mContext, "DOUBLE EVENT " + e.getAction(), Toast.LENGTH_SHORT).show();  
  49.         returnfalse;  
  50.     }  
  51.     @Override
  52.     publicboolean onSingleTapConfirmed(MotionEvent e) {  
  53.         Toast.makeText(mContext, "SINGLE CONF " + e.getAction(), Toast.LENGTH_SHORT).show();  
  54.         returnfalse;  
  55.     }  
  56. }  

STEP 2: 設定手勢識別

我們可以在Activity裡設定手勢識別:

  1. package noodies.blog.csdn.net;  
  2. import android.app.Activity;  
  3. import android.os.Bundle;  
  4. import android.view.GestureDetector;  
  5. import android.view.MotionEvent;  
  6. publicclass GestureTestActivity extends Activity {  
  7.     private GestureDetector mGestureDetector;  
  8.     @Override
  9.     publicvoid onCreate(Bundle savedInstanceState) {  
  10.         super.onCreate(savedInstanceState);  
  11.         setContentView(R.layout.main);  
  12.         mGestureDetector = new GestureDetector(thisnew MyGestureListener(this));  
  13.     }  
  14.     @Override
  15.     publicboolean onTouchEvent(MotionEvent event) {  
  16.         return mGestureDetector.onTouchEvent(event);  
  17.     }  
  18. }  

也可以在自定義的View裡面設定手勢識別:

  1. package noodies.blog.csdn.net;  
  2. import android.content.Context;  
  3. import android.util.AttributeSet;  
  4. import android.view.GestureDetector;  
  5. import android.view.MotionEvent;  
  6. import android.view.View;  
  7. publicclass MyView extends View {  
  8.     private GestureDetector mGestureDetector;  
  9.     public MyView(Context context, AttributeSet attrs) {  
  10.         super(context, attrs);  
  11.         mGestureDetector = new GestureDetector(context, new MyGestureListener(context));  
  12.         setLongClickable(true);  
  13.         this.setOnTouchListener(new OnTouchListener() {  
  14.             publicboolean onTouch(View v, MotionEvent event) {  
  15.                 return mGestureDetector.onTouchEvent(event);  
  16.             }  
  17.         });  
  18.     }  
  19. }  
  • 陷阱


對於自定義View,使用手勢識別有兩處陷阱可能會浪費你的不少時間。

1:View必須設定longClickable為true,否則手勢識別無法正確工作,只會返回Down, Show, Long三種手勢

2:必須在View的onTouchListener中呼叫手勢識別,而不能像Activity一樣過載onTouchEvent,否則同樣手勢識別無法正確工作

  • 測試結果

下面是各種操作返回的手勢序列,數值0表示觸控式螢幕按下,1表示擡起

  1. 單擊:down 0, single up 1, single conf 0  
  2. 短按:down 0, show 0, single up 1  
  3. 長按:down 0, show 0, long 0  
  4. 雙擊:down 0, single up 1, double 0, double event 0, down 0, double event 1  
  5. 滾動:down 0, (show 0), scrool 2...  
  6. 滑動:down 0, (show 0), scrool 2..., fling 1