最近总感觉学过的知识总是忘了;还是应了那句老话,好记性不如烂笔头,所以,还是老老实实记录文字吧;
今天把手势 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;
}