最近總感覺學過的知識總是忘了;還是應了那句老話,好記性不如爛筆頭,所以,還是老老實實記錄文字吧;
今天把手勢 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;
}