Android 中与 Touch 事件分发和消费机制

Android 中与 Touch 事件分发和消费机制

1.相关方法:

  • dispatchTouchEvent(MotionEvent ev)
  • onInterceptTouchEvent(MotionEvent ev)
  • onTouchEvent(MotionEvent ev)

响应这个方法的控件包括: ViewGroup 、View、Activity

2.分发顺序:
分发顺序为dispatchTouchEvent — onInterceptTouchEvent — onTouchEvent

Touch 事件相关方法 方法功能 ViewGroup Activity
dispatchTouchEvent 事件分发 Yes Yes
onInterceptTouchEvent 事件拦截 Tes No
onTouchEvent 事件响应 Yes Yes

需要注意的是如果如果一个View没有添加子View(比如TextView以是最小单元view)将只有onTouchEvent()方法。

3.Android中的事件传递有点类似于JS中事件传递模型。都是基于先捕获然后冒泡的形式:
捕获阶段:事件先由外部的View接受,然后传递给内层的View,依次传递到能够接收此事件的最小View单元,完成捕获过程。
冒泡阶段:事件则从事件源的最小View单元开始,依次向外冒泡,将事件对层传递。(由onTouchEvent方法处理)

事件分发:

当触碰一个控件,就会调用该控件的dispatchTouchEvent()方法。
在学习时前我们需要了解的是:当我们点击一个Button时,就会去调用Button类里面的这个方法,我们知道Button类里面没有这个方法,接着就会去它的父类(TextView)找,同样还是没有,再到TextView的父类(View)里找,我们知道View类里面有dispatchTouchEvent()方法。View类中没有onInterceptTouchEvent()方法。
分发逻辑:
1)返回true,事件会分发给当前View并由dispatchTouch()方法进行消费,同时事件会停止向下传递。
2)返回false:
i)当前View获取的事件来自Activity,事件返回给Activity的onTouch进行消费。
ii)当前View获取的事件来自外层父控件,事件返回给父View的onTouchEvent进行消费。
3)如果返回系统默认的super.dispatchTouchEvent(ev),事件会自动的分发给当前View的onInterceptTouchEvent 方法。

事件拦截

onInterceptTouchEvent()是ViewGroup的一个方法,在外层 View 的 dispatchTouchEvent(MotionEvent ev) 方法返回系统默认的 super.dispatchTouchEvent(ev) 情况下,事件会自动分发给当前View的onInterceptTouchEvent方法。
拦截逻辑:
1)返回true,表示拦截,而是把拦截的事件交由当前View的onTouchEvent方法进行处理。
2)返回false,表示不拦截,当前View上的事件会被传递到子View上,再由子View的dispatchTouchEvent来开始这个事件的分发。
3)返回super.onInterceptTouchEvent(ev),事件默认拦截,并将拦截到的事件交由当前View的onTouchEvent进行处理。

事件响应

在dispatchTouchEvent返回 super.dispatchTouchEvent(ev) 并且 onInterceptTouchEvent返回true 或返回 super.onInterceptTouchEvent(ev)的情况下onTouchEvent 会被调用。
返回false,该事件会从当前view向上传递,,并由上层View的onTouchEvent()来接收,上层如果还是返回false,这个事件就会消失,而且接不到下一次事件。
返回true,该事件接受并消费改事件,将不会向上传递,该过程结束。
返回super.onTouchEvent(ev) 默认处理事件的逻辑和返回false时相同。


举一个ViewGroup简单的例子:现需要实现一个左右滑动的页面(childview(继承ViewGroup)),childview中包含一个listview(上下滚动view。该实例的场景外部滑动(左右)方向和内部滑动(左右)方向不一致。(当然这里如果使用Viewpager和Fragment实现很简单无需考虑这些情况,我要这么做就没有下文了)。

接下来看看这种场景的处理规则:
首先要知道用户是水平滑动还是竖直滑动,根据这个来区分进行拦截:
在listview被触碰的时候,childview的父类ViewGroup中的dispatchTouchEvent先被执行,然后执行它的onInterceptTouchEvent,此时它的子类childview重写了onInterceptTouchEvent()方法,此处根据判断是左滑还是右滑进行判断:
1)如果左右滑动,我们返回true,表示要拦截该事件,接下来执行childview的onTouchEvent()方法(执行左右滑动操作),listview的事件将不会接收。
2)如果上下滑动,我们返回false,表示该事件(childview)继续向下传递,执行listview的dispatchTouchEvent,后面的事情就交给系统处理了。


参考链接:点击进入

你可能感兴趣的:(android)