GestureDetector手勢偵測

簡介

Android系統中有另一個用來偵測觸控手勢的類別GestureDetector,和onTouchEvent()onTouch不同的的地方,onTouchEvent()onTouch()是屬於比較廣義的觸控事件,只回應比較基本觸控事件,如:ACTION_DOWN、ACTION_UP、ACTION_MOVE等等。而像雙擊、長按甚至捲動這些較複雜的動作,就無法回應了,如果應用程式內需要支援更進一步的觸控手勢,可以使用GestureDetector類別來偵測。

GestureDetector類別內提供兩個介面和一個子類別:

interface GestureDetector.OnDoubleTapListener 該介面用來通知雙擊或是單擊確認事件。
interface GestureDetector.OnGestureListener 該介面用來通知有手勢動作發生的事件。
class GestureDetector.SimpleOnGestureListener 一個方便的手勢偵測集合類別,可以用來繼承並實作你感興趣的事件。


建立手勢偵測步驟

  1. 建立自己的手勢類別並繼承類別GestureDetector.SimpleOnGestureListener
  2. 建立GestureDetector物件。
  3. 幫你要偵測手勢的View元件加入onTouchEvent()onTouch()方法。
  4. onTouchEvent()onTouch()內呼叫GestureDetector.onTouchEvent()方法,並傳入系統傳來的MotionEvent物件。在onTouchEvent()onTouch()方法內必須回傳false,否則部分手勢將無法被偵測到。

GestureDetector.SimpleOnGestureListener支援的手勢:

boolean onDoubleTap(MotionEvent e) 快速點擊兩次時發生的事件。
boolean onDoubleTapEvent(MotionEvent e) 當快速點擊兩下時,每一下都會發生一次。
boolean onDown(MotionEvent e) 每次點擊時發生(發生時機相當於ACTION_DOWN)。
boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 當滑動了一段距離後,放開時發生的事件。
void onLongPress(MotionEvent e) 點擊並且停留長時間時會發生。
boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) 當滑動時會持續發生。
void onShowPress(MotionEvent e) 當使用者點擊後,停留較長一點時間,沒有滑動也還沒放開時會發生。
boolean onSingleTapConfirmed(MotionEvent e) 單擊並且沒有發生雙擊事件時發生。Notified when a single-tap occurs.
boolean onSingleTapUp(MotionEvent e) 單擊放開時或是雙擊事件的第一下方開時會發生。


範例

在自定義SimpleOnGestureListener類別內使用快速鍵Ctrl+O並加入覆寫(override)所有手勢事件方法。

import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.View.OnLongClickListener;
import android.view.View.OnTouchListener;
import android.widget.TextView;

public class MyGestureDetectorActivity extends Activity 
{
    TextView txt;
        
    @Override
    protected void onCreate(Bundle savedInstanceState) 
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_my_gesture_detector);
        Log.d("MyGestureDetectorActivity", "onCreate");

        txt = (TextView)findViewById(R.id.txt);
        txt.setText(""); // 清空文字

        // 傾聽TextView上的手勢,該元件layout_width和layout_height皆為match_parent
        txt.setOnTouchListener(new OnTouchListener() 
        {
            // 建立GestureDetector物件,並傳入自己定義的手勢物件(繼承自SimpleOnGestureListener)
            GestureDetector gd = new GestureDetector(MyGestureDetectorActivity.this, new MyGestureDetectorListener());

            @Override
            public boolean onTouch(View v, MotionEvent event) 
            {
                // 呼叫GestureDetector的onTouchEvent()方法,傳入收到的MotionEvent物件
                gd.onTouchEvent(event);

                return false;
            }
        });
    }

    public void addText(String str)
    {
        txt.setText(str + "\n" + txt.getText().toString()); 
    }

    // 自行定義的手勢物件
    class MyGestureDetectorListener extends SimpleOnGestureListener 
    {
        @Override
        public boolean onSingleTapUp(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onSingleTapUp");
            addText("onSingleTapUp");
            return super.onSingleTapUp(e);
        }

        @Override
        public void onLongPress(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onLongPress");
            addText("onLongPress");
            super.onLongPress(e);
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX,
        float distanceY) 
        {
            Log.d("MyGestureDetectorListener", "onScroll");
            addText("onScroll");
            return super.onScroll(e1, e2, distanceX, distanceY);
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
        float velocityY) 
        {
            Log.d("MyGestureDetectorListener", "onFling");
            addText("onFling");
            return super.onFling(e1, e2, velocityX, velocityY);
        }

        @Override
        public void onShowPress(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onShowPress");
            addText("onShowPress");
            super.onShowPress(e);
        }

        @Override
        public boolean onDown(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onDown");
            addText("onDown");
            return super.onDown(e);
        }

        @Override
        public boolean onDoubleTap(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onDoubleTap");
            addText("onDoubleTap");
            return super.onDoubleTap(e);
        }

        @Override
        public boolean onDoubleTapEvent(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onDoubleTapEvent");
            addText("onDoubleTapEvent");
            return super.onDoubleTapEvent(e);
        }

        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) 
        {
            Log.d("MyGestureDetectorListener", "onSingleTapConfirmed");
            addText("onSingleTapConfirmed");
            return super.onSingleTapConfirmed(e);
        }
    }
}