前言
关于Android View事件分发机制的一个小结,基于他人分析以及个人理解,方便自己记录以及回忆,使用了一些UML图和流程图对部分流程进行了细化,并加入了自己的理解,期间参考了几篇比较优秀(不同博文可能针对的Android代码版本不同,存在些许出入,但是大致逻辑一致)的关于事件分发机制的博文,已在参考链接中列出。
该篇博文更适合那些对事件分发机制基本了解但是仍然缺少一个系统化轮廓的朋友,只是一个总结而非教程,如果完全没有概念的话先从参考链接的博文开始看起!然后再回过头来看这个总结。
如果发现有什么问题,欢迎留言拍砖!
Activity的事件分发逻辑
- 点击事件最先传递给当前的Activity,由Activity的dispatchToucnEvent来进行事件分发,具体的工作由Activity内部的Window来完成,Window会将事件传递给DecorView,DecorView一般就是当前界面的底层容器(即setContentView所设置的View的父容器),通过Activity.getWindow.getDecorView()可以获得
- 如果所有的View的onTouchEvent都返回了false,那么Activity的onTouchEvent就会被调用
- Window的唯一实现是PhoneWindow
- PhoneWindow中通过DecorView往下分发事件
- 通过((ViewGroup))getWindow().getDecorView().findViewById(android.R.id.content).getChildAt(0)可以获得Activity所设置的View
- DecorView继承自FrameLayout且是父View,所以最终事件会传递给View
ViewGroup以及View的事件分发逻辑
- ViewGroup中的onInterceptTouchEvent用来控制ViewGroup是否拦截事件向下传递
- ViewGroup的主要的任务是找一个Target,并且用这个target传递事件
- 在Down并且不拦截的时候会多出一个寻找Target的过程,在这个过程中遍历子View,如果子View的dispatchTouch为true(如果这里返回false的话,那么接下来的action就不会继续传递,因为这时的target就为空,target为空的话,就会触发ViewGroup作为一个View的dispatchTouchEvent()方法),则这个子View就是当前ViewGroup的Target。找Target是处理Down事件时候特有的,其他事件不会触发找Target。
- 那么上面说的View的dispatchTouchEvent一定会返回true吗?默认情况下只要View是Clickable或者LongClickable,就一定消费事件,即返回true
- 找到Target之后如果再次调用ViewGroup的dispatchTouchEvent,就用经过一系列逻辑判断继续调用Target的dispatchTouchEvent
- View的onTouchEvent中,当action == MotionEvent.ACTION_UP时,就会触发View的performClick(),所以onClick会晚于onTouch
总结和参考
有没有发现,Android View的事件分发就是一个活生生的基于责任链模式实现的经典案例!
建议:可以根据自己不同的理解程度参考如下博文:
http://www.nowamagic.net/academy/detail/50160216
http://blog.youkuaiyun.com/duo2005duo/article/details/51604119
http://blog.youkuaiyun.com/guolin_blog/article/details/9153747
《Android开发艺术探索》