前言
Android事件管理机制是一名专业Android研发工程师必须要了解的核心知识之一,深入了解一下该机制无论对我们日常开发还是找工作,乃至于对我们的架构思想都有很大的帮助。Android中我们用到的最多的事件是InputEvent,主要是两类:MotionEvent和KeyEvent。由于事件传递模型基本一致,我将以更常用到的MotionEvent为目标来讲解。
根据实际开发的需要,本文仅讲解touch事件在viewTree中的传递机制,为广大开发者搞清原理、扫清障碍。文章参考了Kelin童鞋的图解Android事件传递机制,写的很好大家也可以去看看。
本篇是图解Android系列第一篇,更多文章敬请关注后续文章。如果这篇文章对大家学习Android有帮助,还望大家多多转载。学习小组QQ群: 193765960。
版权归作者所有,如有转发,请注明文章出处:https://xiaodanchen.github.io/archives/
Touch事件的分发、传递、消费所涉及的类与函数
老规矩,让我们先来看一张类图:
- View类定义了两个Touch事件传递分发的函数:
- public boolean dispatchTouchEvent(MotionEvent event)
- public boolean onTouchEvent(MotionEvent event)
- ViewGroup继承自View类,其重写了定义了两个 Touch事件传递分发的函数
- @Override public boolean dispatchTouchEvent(MotionEvent ev)
- public boolean onInterceptTouchEvent(MotionEvent ev)
- Activity类定义了两个Touch事件传递分发的函数:
- public boolean dispatchTouchEvent(MotionEvent event)
- public boolean onTouchEvent(MotionEvent event)
- Activity类的viewRoot实际上是PhoneWindow的DecorView(ViewGroup)
- DecorView维护了一个LinearLayout对象,这个对象包括两部分:TitleView和ContentViews(FrameLayout)
- 我们定义的layout.xml其实是被加载到TitleView和ContentViews中的
Touch事件在Activity的viewTree中的传递分发,如图
- 箭头的上面字代表方法返回值:return true、return false、return super.xxxxx(),super 的意思是调用父类实现。
- dispatchTouchEvent和 onTouchEvent的框里有个[true—->消费]的字,表示的意思是如果方法返回true,那么代表事件就此消费,不会继续往别的地方传了,事件终止。
- 目前所有的图的事件是针对ACTION_DOWN的,对于ACTION_MOVE和ACTION_UP我们最后做分析。
事件分发入口:Activity类的dispatchTouchEvent()方法
|
|
ViewGroup 中touch事件是如何传递的
ViewGroup的dispatchTouchEvent()方法
|
|
ViewGroup的dispatchTransformedTouchEvent()方法
|
|
ViewGroup的onInterceptTouchEvent()方法
|
|
View 中touch事件是如何传递的
View的onInterceptTouchEvent()方法
|
|
View的onTouchEvent()方法
|
|
如果事件不被中断,整个事件流向是一个类U型图,我们来看下这张图,可能更能理解U型图的意思。
注意:这张图只是一张事件的传递模型的示意图,事件传递的实际实现细节跟图中不太一致,但最终事件的传递方向是一致的。
通过代码我们注意到,每一层的dispatchtouchevent()都是该层的事件的入口,在每一层的逻辑都大致遵循如下调用规则:
- dispatchtouchevent捕获到上层分发过来的事件
- 调用oninterceptTouchevent用来逻辑判断该事件是否需要在本层处理
- 如果oninterceptTouchevent 返回false,则调用下一层的viewtree的dispatchtouchevent(递归),子viewtree的返回结果会作为本层dispatchtouchevent的结果返回
- 如果oninterceptTouchevent返回true,则调用本层的ontouchevent方法
- ontouchevent的逻辑处理结果会返回给dispatchtouchevent座位结果返回
- 最终本层的dispatchtouchevent的处理结果会返回给父view
整个viewtree其实都是在按照同样的逻辑进行着层层的递归。
希望读者能够好好的把握一下代码和递归逻辑,这样在我们的view中就可以根据实际需要灵活使用时间分发、拦截和处理的三种接口,灵活的控制事件的传递和消费。
ACTION_MOVE和ACTION_UP事件
我们上文中讲到的事件传递流程是ACTION_DOWN的处理流程。
由于ACTION_DOWN事件是touch事件的第一个事件,所以其处理流程会相对复杂。而后续的一系列其他事件,其处理逻辑收到ACTION_DOWN事件的处理结果的影响而更加的智能。系统不会傻傻的把前人走过的死路让后人再走一遍。换句话说,一旦ACTION_DOWN事件找到了target,后续的一些列事件就会直达target,而不会再分发往更底层进行逻辑迭代。
还是那句话,看图(再次感谢kelin童鞋做出了这么优雅的图片):
- 红色的箭头代表ACTION_DOWN 事件的流向
- 蓝色的箭头代表ACTION_MOVE 和 ACTION_UP 事件的流向
本篇是Glide框架及源码解析的第一篇,更多文章敬请关注后续文章。版权归作者所有,如有转发,请注明文章出处:原文链接)