Android 手勢識別(單擊 雙擊 擡起 短按 長按 滾動 滑動)
對於觸控式螢幕,其原生的訊息無非按下、擡起、移動這幾種,我們只需要簡單過載onTouch或者設定觸控偵聽器setOnTouchListener即可進行處理。不過,為了提高我們的APP的使用者體驗,有時候我們需要識別使用者的手勢,Android給我們提供的手勢識別工具GestureDetector就可以幫上大忙了。
- 基礎
GestureDetector的工作原理是,當我們接收到使用者觸控訊息時,將這個訊息交給GestureDetector去加工,我們通過設定偵聽器獲得GestureDetector處理後的手勢。
GestureDetector提供了兩個偵聽器介面,OnGestureListener處理單擊類訊息,OnDoubleTapListener處理雙擊類訊息。
OnGestureListener的介面有這幾個:
- // 單擊,觸控式螢幕按下時立刻觸發
- abstractboolean onDown(MotionEvent e);
- // 擡起,手指離開觸控式螢幕時觸發(長按、滾動、滑動時,不會觸發這個手勢)
- abstractboolean onSingleTapUp(MotionEvent e);
- // 短按,觸控式螢幕按下後片刻後擡起,會觸發這個手勢,如果迅速擡起則不會
- abstractvoid onShowPress(MotionEvent e);
- // 長按,觸控式螢幕按下後既不擡起也不移動,過一段時間後觸發
- abstractvoid onLongPress(MotionEvent e);
- // 滾動,觸控式螢幕按下後移動
- abstractboolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
- // 滑動,觸控式螢幕按下後快速移動並擡起,會先觸發滾動手勢,跟著觸發一個滑動手勢
- abstractboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
OnDoubleTapListener的介面有這幾個:
- // 雙擊,手指在觸控式螢幕上迅速點選第二下時觸發
- abstract
boolean onDoubleTap(MotionEvent e);- // 雙擊的按下跟擡起各觸發一次
- abstractboolean onDoubleTapEvent(MotionEvent e);
- // 單擊確認,即很快的按下並擡起,但並不連續點選第二下
- abstractboolean onSingleTapConfirmed(MotionEvent e);
有時候我們並不需要處理上面所有手勢,方便起見,Android提供了另外一個類SimpleOnGestureListener實現瞭如上介面,我們只需要繼承SimpleOnGestureListener然後過載感興趣的手勢即可。
- 應用
STEP 1: 建立手勢偵聽物件
- package noodies.blog.csdn.net;
- import android.content.Context;
- import android.view.MotionEvent;
- import android.view.GestureDetector.SimpleOnGestureListener;
- import android.widget.Toast;
- publicclass MyGestureListener extends SimpleOnGestureListener {
- private Context mContext;
- MyGestureListener(Context context) {
- mContext = context;
- }
- @Override
- publicboolean onDown(MotionEvent e) {
- Toast.makeText(mContext, "DOWN " + e.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicvoid onShowPress(MotionEvent e) {
- Toast.makeText(mContext, "SHOW " + e.getAction(), Toast.LENGTH_SHORT).show();
- }
- @Override
- publicboolean onSingleTapUp(MotionEvent e) {
- Toast.makeText(mContext, "SINGLE UP " + e.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicboolean onScroll(MotionEvent e1, MotionEvent e2,
- float distanceX, float distanceY) {
- Toast.makeText(mContext, "SCROLL " + e2.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicvoid onLongPress(MotionEvent e) {
- Toast.makeText(mContext, "LONG " + e.getAction(), Toast.LENGTH_SHORT).show();
- }
- @Override
- publicboolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
- float velocityY) {
- Toast.makeText(mContext, "FLING " + e2.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicboolean onDoubleTap(MotionEvent e) {
- Toast.makeText(mContext, "DOUBLE " + e.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicboolean onDoubleTapEvent(MotionEvent e) {
- Toast.makeText(mContext, "DOUBLE EVENT " + e.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- @Override
- publicboolean onSingleTapConfirmed(MotionEvent e) {
- Toast.makeText(mContext, "SINGLE CONF " + e.getAction(), Toast.LENGTH_SHORT).show();
- returnfalse;
- }
- }
STEP 2: 設定手勢識別
我們可以在Activity裡設定手勢識別:
- package noodies.blog.csdn.net;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- publicclass GestureTestActivity extends Activity {
- private GestureDetector mGestureDetector;
- @Override
- publicvoid onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- mGestureDetector = new GestureDetector(this, new MyGestureListener(this));
- }
- @Override
- publicboolean onTouchEvent(MotionEvent event) {
- return mGestureDetector.onTouchEvent(event);
- }
- }
也可以在自定義的View裡面設定手勢識別:
- package noodies.blog.csdn.net;
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- import android.view.View;
- publicclass MyView extends View {
- private GestureDetector mGestureDetector;
- public MyView(Context context, AttributeSet attrs) {
- super(context, attrs);
- mGestureDetector = new GestureDetector(context, new MyGestureListener(context));
- setLongClickable(true);
- this.setOnTouchListener(new OnTouchListener() {
- publicboolean onTouch(View v, MotionEvent event) {
- return mGestureDetector.onTouchEvent(event);
- }
- });
- }
- }
- 陷阱
對於自定義View,使用手勢識別有兩處陷阱可能會浪費你的不少時間。1:View必須設定longClickable為true,否則手勢識別無法正確工作,只會返回Down, Show, Long三種手勢
2:必須在View的onTouchListener中呼叫手勢識別,而不能像Activity一樣過載onTouchEvent,否則同樣手勢識別無法正確工作
- 測試結果
下面是各種操作返回的手勢序列,數值0表示觸控式螢幕按下,1表示擡起
- 單擊:down 0, single up 1, single conf 0
- 短按:down 0, show 0, single up 1
- 長按:down 0, show 0, long 0
- 雙擊:down 0, single up 1, double 0, double event 0, down 0, double event 1
- 滾動:down 0, (show 0), scrool 2...
- 滑動:down 0, (show 0), scrool 2..., fling 1