Android 手勢學習 GestureDetector

最近總感覺學過的知識總是忘了;還是應了那句老話,好記性不如爛筆頭,所以,還是老老實實記錄文字吧;

今天把手勢 GestureDetector 記錄一下;

一、簡介

我們知道,當我們要處理一下複雜的手勢時,如果還使用 onTouchListener ,那麼則需要自己額外的去寫一些判斷邏輯;當然,google 已經爲我們封裝好了手勢的實現類 GestureDetector ,只需要實現它的 Listener ,即可拿到自己想要的方法。
GestureDetector 提供了三個接口和一個內部類:

  • 接口 OnGestureListener
  • 接口 OnDoubleTapListener
  • 接口 OnContextClickListener
  • 內部類 SimpleOnGestureListener
    其中 OnContextClickListener 很容易聯想到 context 的點擊,但其實不是,是指外接設備,比如藍牙筆按下時觸發,在 API 23 後加入的,如果偵聽 onContextClick(MotionEvent),則必須在 View 的 onGenericMotionEvent(MotionEvent)中調用 GestureDetector 的 OnGenericMotionEvent(MotionEvent)。一般也沒怎麼用到,所以這裏不做解釋,

二、手勢介紹

手勢介紹這裏,我們就簡單介紹一下OnGestureListener 和 OnDoubleTapListener 即可。

2.1 OnGestureListener

OnGestureListener 爲GestureDetector 的一個方法,它的實現方法如下:

    class GestureListenerDemo implements GestureDetector.OnGestureListener{

        @Override
        public boolean onDown(MotionEvent e) {
            /**
             * 按下屏幕就會出發,需要返回true來消費這個事件,通過GestureDetector 源碼就知道,
             * 返回true後,mDetector.onTouchEvent(event) 也會返回突然, 這樣 onTouchEvent 的事件纔不會繼續傳遞
             */
            Log.d(TAG, "zsr onDown: ");
            return false;
        }

        @Override
        public void onShowPress(MotionEvent e) {
            /**
             * 當按下超過180ms時,就會觸發,一般我們用這個來實現點擊背景之類的
             */
            Log.d(TAG, "zsr onShowPress: ");
        }

        @Override
        public boolean onSingleTapUp(MotionEvent e) {
            /**
             * 相當於 up 事件
             */
            Log.d(TAG, "zsr onSingleTapUp: ");
            return false;
        }

        @Override
        public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
            /**
             * 監聽屏幕滑動,其中 e2 第二個觸摸事件,distanceX 和 distanceY
             * 則爲滑動距離
             */
            Log.d(TAG, "zsr onScroll: ");
            return false;
        }

        @Override
        public void onLongPress(MotionEvent e) {
            /**
             * 當手指按住屏幕不放,
             */
            Log.d(TAG, "zsr onLongPress: ");
        }

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            /**
             * 當手指快速滑動屏幕,則會觸發 velocityX,velocityY 表示每秒滑動的距離(像素)
             */
            Log.d(TAG, "zsr onFling: ");
            return false;
        }
    }

GestureDetector 使用如下:

// 1、 拿到 GestureDetector 實例
mDetector = new GestureDetector(new GestureListenerDemo());
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 2、在 onTouchEvent 中,調用 GestureDetector 的onTouchEvent
        return mDetector.onTouchEvent(event);

    }

上面的註釋已經很清楚了,需要注意的是 onDown 需要返回 true,否則 onscroll 等方法不會調用,這裏是因爲要onTouchEvent 消費這些事件,具體可以看看事件分發機制。

2.2 OnDoubleTapListener

OnDoubleTapListener 爲雙擊時調用的接口,它的實現也比較簡單,首先繼承該接口:

class DoubleListenerDemo implements GestureDetector.OnDoubleTapListener{

   @Override
   public boolean onSingleTapConfirmed(MotionEvent e) {
       /**
        * 點擊事件,不像onSingleTapUp,當雙擊時 onSingleTapConfirmed 不會被調用
        */
       Log.d(TAG, "zsr onSingleTapConfirmed: ");
       return false;
   }

   @Override
   public boolean onDoubleTap(MotionEvent e) {
       /**
        * 雙擊,當第二下點擊,down 事件觸發
        */
       Log.d(TAG, "zsr onDoubleTap: ");
       return false;
   }

   @Override
   public boolean onDoubleTapEvent(MotionEvent e) {
       /**
        * 雙擊時觸發,且 MotionEvent 會繼續觸發,可以監聽 up 事件,
        * 在up事件處理邏輯
        */
       Log.d(TAG, "zsr onDoubleTapEvent: "+e.getAction());
       return false;
   }
}

然後需要在 GestureDetector 這裏把監聽事件添加進去:

mDetector = new GestureDetector(new GestureListenerDemo());
mDetector.setOnDoubleTapListener(new DoubleListenerDemo());

這裏有幾個接口要解釋一下:
onSingleTapConfirmed() 和 onSingleTapUp 的區別在於,onSingleTapConfirmed 在雙擊事件時並不會被調用,而 onSingleTapUp 則是會繼續調用,所以一些細微的邏輯處理可以從這裏下手;
onDoubleTap 和 onDoubleTapEvent 的區別在於onDoubleTap 是第二次點擊的 down事件時,就會觸發,而 onDoubleTapEvent 方法中的 MotionEvent 都會被觸發,所以也可以在這裏做一些邏輯。

2.3 SimpleOnGestureListener

從上面看,還是有些奇怪的,我們除了要設置 OnGestureListener,如果監聽雙擊,還得通過 setOnDoubleTapListener 把OnDoubleTapListener設置一下;其實 google 也考慮到了,所以纔有了 SimpleOnGestureListener 這個內部類;
該類實現了 OnGestureListener,setOnDoubleTapListener 和 OnContextClickListener 的方法,只是裏面都是空的,需要自己去實現。且不需要的可以不用重寫,所以這個也是用的最多的。
如下,我們只需要雙擊事件:

    class  SimpleDemo extends GestureDetector.SimpleOnGestureListener{
        @Override
        public boolean onDown(MotionEvent e) {
            return true;
        }
        @Override
        public boolean onDoubleTap(MotionEvent e) {
            Log.d(TAG, "zsr 雙擊666");
            return false;
        }


    }

調用兩個參數的構造函數即可:

mDetector = new GestureDetector(context,new SimpleDemo());

三、實例

經過上面的學習,接着我們學習一下,左滑退出,右滑進入其他 activity 的實例,可以很快想到用 onFlat 方法:

        @Override
        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
            //實現左滑和右滑
            float distanceX = e2.getX() - e1.getX();
            if (distanceX > 100 && velocityX > 200){
                Log.d(TAG, "zsr onFling: 左滑退出");
            }
            if (distanceX < -100 && velocityX < -200){
                Log.d(TAG, "zsr onFling: 右滑進入其他activity");
            }
          //  Log.d(TAG, "onFling:迅速滑動,並鬆開");
            return false;
        }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章