看完这篇还不会 GestureDetector 手势检测,我跪搓衣板!

android 开发过程中,我们经常需要对一些手势,如:单击、双击、长按、滑动、缩放等,进行监测。这时也就引出了手势监测的概念,所谓的手势监测,说白了就是对于 GestureDetector 的用法的使用和注意要点的学习。注:由于缩放手势独有的复杂性,我打算后期将其单独拿出来归纳总结。

像网上其他将手势监听的博客一样,本文将以双击事件为引子,逐步展开探讨 Android 手势监听,你需要知道的点点滴滴,还是那句话:看完这篇还不会 GestureDetector 手势检测,我跪搓衣板!

双击 666

对于一个 Android 新手而言,如果需要你实现一个双击功能,我们一般会怎么想呢?

May Be

首先我们重写 onTouchEvent 方法

当第一次点击后,咱们先判断是否为需要监听的控件

如果是则 new 一个线程,开始倒计时(如 1s)

如果在这个倒计时的期间,再次调用了点击事件

判断成功、发生双击事件⌚️

But
这实在是太复杂了,你又要控制时间,又要判断控件等等等等。所以,我们因该如何解决呢?手势监听的使用

GestureDetector 使用

我的理解是 GestureDetector 是 Android 中,专门用来进行手势监听的一个对象,在他的监听器中,我们通过传入 MotionEvents 对象,就可以在各种事件的回调方法中各种手势进行监测。举个例子: GestureDetector 的 OnGestureListener 就是一种回调方法,就是说在获得了传入的这个 MotionEvents 对象之后,进行了处理,我们通过重写了其中的各种方法(单击事件、双击事件等等),就可以监听到单击,双击,滑动等事件,然后直接在这些方法内部进行处理。

盗张没啥软用的图美化界面

使用方法

首先,创建一个 SimpleOnGestureListener 回调方法对象,并对其中各个方法进行重写

根据这个 listener 对象,实例化出 GestureDetector 对象

对目标控件重写 setOnTouchListener 方法,并在其中调用 detector 对象的 onTouchEvent 方法即可

简单易懂,一分钟搞定

@Override protected void onResume() { button.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { return detector.onTouchEvent(event); } }); super.onResume(); } private void iniGestureListener(){ GestureDetector.SimpleOnGestureListener listener = new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onDoubleTap(MotionEvent e) { MyToast.makeToast(GestureDetectorActivity.this, "double click up!"); return super.onDoubleTap(e); } detector = new GestureDetector(GestureDetectorActivity.this, listener); }

运行结果

Looper 注册

如果哪位好奇的老铁,尝试着在线程中创建这个 detector 对象(比如下面这种)。那么运行时就可能出现程序崩溃的情况,这是为什么呢?

new Thread(){ @Override public void run() { super.run(); detector = new GestureDetector(GestureDetectorActivity.this, listener); } }.start();

其实在 GestureDetector 被实例化时,内部会自动创建一个 Handler 用于处理数据,所以如果你在主线程中创建 GestureDetector,那么这个 GestureDetector 内部创建的 Handler 会自动获得主线程的 Looper。也是因此:如果你在一个没有创建 Looper 的子线程中创建 GestureDetector 则需要传递一个带有 Looper 的 Handler 给它,否则就会因为无法获取到 ==Looper== 导致创建失败。

解决

既然问题出现了,那要怎么解决呢。既然是缺少活动中的 Looper ,那么将活动中的 ==Looper== 传入就是。观察 ==detector== 的构造方法,发现其一共有种方法,其中我们常用的方法有两种,首先是我们在主线程中用的那种,另外一种就是我们现在要用的,在子线程中,能传入 Looper 的 构造方法:
| public GestureDetector(Context context, OnGestureListener listener) |
|--|
| GestureDetector(Context context, GestureDetector.OnGestureListener listener, Handler handler) |

方案一
传入一个保有 Looper 对象的 Hander

new Thread(){ @Override public void run() { super.run(); detector = new GestureDetector(GestureDetectorActivity.this, listener, new Handler(Looper.getMainLooper())); } }.start();

方案二
跟方法已一样,只是把 Hander 拿出来单独创建罢了

new Thread(){ @Override public void run() { super.run(); Handler handler = new Handler(Looper.getMainLooper()); detector = new GestureDetector(GestureDetectorActivity.this, listener, handler); } }.start();

方案三
在主线程中创建 Hander ,这样就不用在创建 Hander 时,传入主线程的 Looper

final Handler handler = new Handler(); new Thread(){ @Override public void run() { super.run(); detector = new GestureDetector(GestureDetectorActivity.this, listener, handler); } }.start();

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpffgf.html