事件分发机制
Android 中与 Touch 事件相关的方法包括:
dispatchTouchEvent(MotionEvent ev)
onInterceptTouchEvent(MotionEvent ev)
onTouchEvent(MotionEvent ev);
能够响应这些方法的控件包括:Activity、ViewGroup和View,方法与控件的对应关系如下表所示:
Touch事件相关方法 | 方法功能 | Activity | ViewGroup | View |
---|---|---|---|---|
dispatchTouchEvent(MotionEvent ev) | 事件分发 | Yes | Yes | Yes |
onInterceptTouchEvent(MotionEvent ev) | 事件拦截 | No | Yes | No |
onTouchEvent(MotionEvent ev) | 事件响应 | Yes | Yes | Yes |
从表中可以看出,Activity和View都没有onInterceptTouchEvent(MotionEvent ev)方法,所以它们不能对事件进行拦截操作,可以拦截的只有ViewGroup。
三个方法的执行顺序如下:
dispatchTouchEvent(MotionEvent ev) -> onInterceptTouchEvent(MotionEvent ev) -> onTouchEvent(MotionEvent ev)
事件分发的过程具体如下图所示:
每个方法都有三种返回状态:Super、True、False。三种返回状态的描述如下:
- Super:调用父类方法
- True:消费事件,即事件不继续往下传递
- False:不消费事件,事件也不继续往下传递 或者交由给父控件onTouchEvent()处理
接下来我们分析Activity、ViewGroup和View中的事件分发。
事件流程分析
- Activity
Android系统默认不会拦截所有的事件,当事件传递到Activity时,dispatchTouchEvent会先接收到事件,这里有两种情况:
Super:默认不拦截事件,传递给子ViewGroup或View的dispatchTouchEvent()方法。
True或False:消费掉事件,不再向下传递。(猜测事件传递给DecView消费)
所以,在开发过程中,尽量不要在Activity中的dispatchTouchEvent()方法中返回True或False,会导致所有控件都无法接收事件。
- ViewGroup
当ViewGroup的dispatchTouchEvent()方法接收到事件时,有三种情况需要考虑:
Super:分发事件,将事件传递给当前的onInterceptTouchEvent()方法。
True:不分发事件,将事件传递给父容器的dispatchTouchEvent()方法去处理。
False:不分发事件,将事件传递给父容器的OnTouchEvent()消费掉。
当dispatchTouchEvent()为Super的情况下,ViewGroup的onInterceptTouchEvent()方法会响应,这里有两种情况:
Super或False:不拦截事件,将事件传递给子ViewGroup或View的dispatchTouchEvent()方法。
True:拦截事件,当前的OnTouchEvent()方法会响应。
OnTouchEvent也有两种情况:
Super或False:将事件传递到父容器的OnTouchEvent去处理。
True:直接消耗掉事件。
- View
当View的dispatchTouchEvent()方法接收到事件时,有三种情况:
Super:分法事件,将事件传递给当前的OnTouchEvent去处理。
True:不分发事件,将事件传递给父容器的dispatchTouchEvent()方法去处理。
False:将事件传递到父容器的OnTouchEvent()去处理。
当View的OnTouchEvent()方法接收到事件时,有两种情况:
Super或False:传递事件到父容器的OnTouchEvent()去处理。
True:在当前OnTouchEvent()方法中消耗事件。
注意:在dispatchTouchEvent()中,返回True和False后,后续的Move和Up事件会继续分发到该View或ViewGroup。
总结:Android事件的机制非常的复杂,图中还是存在一些错误以及一些没有讲到的地方,需要自己动手去验证才最实际。