前言
事件分发机制是 Android 中的重点和难点,也是解决滑动冲突的理论基础。
本文参考书: 《Android 开发艺术探索》
参考的大神:http://www.gcssloop.com/customview/dispatch-touchevent-theory
正文
1. 事件分发机制实际上是 MotionEvent ( 点击事件 ) 的传递规则。
2. 事件分发机制涉及的三个方法
3. View 事件的传递流程
View 没有 onInterceptTouchEvent 方法,一旦有点击事件传递给它,那么它的 onTouchEvent 方法就会被调用
View 的 onTouchEvent 方法默认都会消耗事件(返回 true),除非是不可点击的( clickable 和 longClickable 同时为 false),View 的 longClickable 属性默认都为 false ,而 clickable 属性分情况,比如 Button 默认为 true ,TextView 默认为 false
View 的 enable 属性不影响 onTouchEvent 方法的返回值,哪怕是 disable 状态,只要 clickable 或者 longClickable 有一个为 true ,那么它的 onTouchEvent 就返回 true。
4. ViewGroup 事件的传递流程
5. 一些注意事项
1. 所谓的点击事件,是指从 down 事件开始,中间可能含有数量不定的 move 事件,最终以 up 事件结束的一系列事件,称为:同一个事件序列
2. 某个 View 一旦决定拦截事件,那么这一个事件序列都有它来处理。
3. 某个 View 一旦开始处理事件,如果它不消耗 ACTION_DOWN 事件( onTouchEvent ),那么同一事件序列中的其他事件都不会再交给它来处理,并且事件将重新交给它的父元素去处理,即父元素的 onTouchEvent 会被调用。
4. 事件的传递过程都是由外向内的。
5. onClick 发生的前提是当前 View 是可点击的,并且收到了 down 和 up 事件。
6. actvity 对点击事件的分发过程
1. 当一个点击操作发生时,事件最先传递给 Activity ,由 Activity 的 dispatchTouchEvent 来进行事件的分发,具体工作是由 Activity 内部的 Window 来完成的,Window 会将事件传递给 DecorView ,然后将事件传递给 Activity 的顶级 View ,也就是设置的 setContentView() ;
|
|
2.Window 是个抽象类,其 superDispatchTouchEvent 方法也是抽象方法,
|
|
在 Activity 源码中有这样一行代码:
|
|
从而可以知道 Window 类的实现类为 PhoneWindow ,而实际上 PhoneWindow 是其唯一的一个实现类
Android SDK 隐藏了 PhoneWindow 类源码,本人只好从网上找了源码,看 superDispatchTouchEvent 方法
|
|
从这里可以看出 PhoneWindow 将事件传递给了 mDecor,也就是 DecorView ,其类如下:
|
|
实际上 DecorView 是一个 FrameLayout ,而我们通过 setContentView 设置的 View 就是其一个子类。
然后,DecorView 就会将事件传递给 Activity 设置的 View,也就是顶级 View
接下来就是 View 对点击事件的分发过程了。
7. View 对点击事件的分发过程
之前的 第 2 条、第 3 条和第 4 条 都讲过了,下边再叙述几点:
点击事件到达顶级 View 以后 (一般是一个 ViewGroup )
- 如果顶级 ViewGroup 拦截事件的情况下,设置了 OnTouchListener ,则 onTouch 会被调用,反之会调用 onTouchEvent ,也就是说,如果都提供的话,onTouch 会屏蔽掉 onTouchEvent 。OnTouchListener 的优先级高于 onTouchEvent