View事件分发源码完整图解
最近在看Android开发艺术探索,这真是一本好书,比我之前看的Android群英传讲的深刻许多。所以在边看边写笔记,原本想等看完之后完整的发一篇博客的,但是看到View事件分发的时候,感觉这是一个重头戏,所以做了一张图以后备用,现在先发出来。、
注意:如果能结合源码中ViewGroup的dispatchTouchEvent()和View的dispatchTouchEvent()方法一起看这张图,效果会好很多,当然本图不可能完全正确,仅供参考,如果大家有什么发现也可以直接和我讨论。
由于图片的信息量很大,建议大家可以右键保存下来慢慢啃。
最后我总结了一下View事件分发的几点策略,以下策略都可以在上面的图中找到依据。
- 从手指触摸屏幕到离开屏幕会产生:down->move->…->move->up。这一系列事件,android系统倾向于让某一个View处理这一整个事件序列。
- ViewGroup中,每次down事件都会让ViewGroup的标记重置。
- View一般来说是不需要拦截事件的,因为当事件传递到View的时候,其要么消耗要么返回给父ViewGroup。而ViewGroup如果需要先子View处理事件的话,就可以拦截事件。一旦ViewGroup选择了拦截事件,那么后面同一序列的事件将不会继续下传,都给本ViewGroup处理。(注意:这里有个前提条件就是事件能够传到本ViewGroup中,若其上层的ViewGroup拦截了事件的话,那么同样序列的事件都会给上层ViewGroup处理)
- 若一个ViewGroup决定开始拦截事件的话,那么其onInterceptTouchEvent()方法就不会再调用,这个可以看成(2)的补充。
- 如果最底层的View不消耗down,那么事件会重新返回到其父ViewGroup并调用父ViewGroup的onTouchEvent(),同理可以把父ViewGroup看作View,重复刚刚的行为直到传到Activity的onTouchEvent()。需要注意的是:View不消耗down事件之后,那么同一事件序列的其他事件都不会再交给该View了,而是转交给上一次消耗了down事件的ViewGroup,除非事件在向下传递的时候已经被拦截了。
- 如果底层的View只消耗down事件的话,那么其还是能接受到其他同一序列的事件的。但是此时,同一序列的其他事件就不会再给ViewGroup了,而是直接给Activity的onTouchEvent()
- ViewGroup默认不拦截任何事件即,onInterceptTouchEvent()默认返回false。
- View的onTouchEvent()默认都是会消耗事件的,即默认返回true。除非该View既不可点击,又不可长按。
- View的属性enable不影响onTouchEvent()的返回值,哪怕该View是disable的,只要能点击或者长按onTouchEvent()就会返回true。
- 当android系统处理down事件的时候,会维护一条View链表,这条链表是down事件走过的View形成的。所以在down事件之后,系统无需再遍历当前的View树,寻找事件所在的View区域。