最近想复习一下View事件传递的知识,之前写过好多自定义控件,可最近没咋接触这块知识,又快忘了,所以上网搜一下资料,发现大部分的资料都不全,很多都存有漏洞,甚至是错误的,包括在最近看的一本书 《Android 框架体系架构》上面的介绍,图片,也存在一些错误 ,所以自己通过看源码以及观察代码执行结果来分析事件传递的真理.
目录
本文从事件类型、事件处理方法两个层面结合来分析.
1、基本流程与注意点
先看一张图,图中所画的流程,是一个简单的,完整的事件流程图,图层嵌套 由外到内 为Activity -->Viewgroup1-->Viewgroup2-->View .绘图功底不太好,敬请谅解:
注意点:图中所画的是一个点击事件的流程图,为什么说是点击事件呢,因为移动、抬起、取消事件的流程跟他不一样,他们都会收到点击事件流程的限制,总结一句话就是,点击事件被处理的那一层View(Activity、Viewgroup),将会是后续的移动、抬起、取消事件所能到达的最内层(或最底层),举个例子:
在一套完整的手势当中(点击>滑动>抬起),点击事件被上图中的Viewgroup2# onTouchEvent所消费(返回true),点击事件到此终止,接下来的移动事件,抬起事件,到达Viewgroup2#dispatchTouchEvent()之后,如果返回false(因为返回true,事件结束不再处理),则事件直接由Viewgroup2#onTouchEvent()处理,不再经过interceptTouchEvent(),也就是说,系统会认为Viewgroup2是一个View, 忽略内部所有子控件,不再向内传递事件,且不调用interceptTouchEvent 方法(可以把他理解为一个View 而不是viewgroup 了).
1、总结:
注:“任何事件”表示 包括点击、滑动、抬起、取消手势.
一、分发器(dispatchTouchEvent()) :
1、处理任何事件——返回true,则事件结束,不再传递.
2、但是,处理任何事件——返回False,事件都会走到本层的拦截器(interceptTouchEvent())处理吗? 第一张图片下面的说明已经告诉我们结果,答案是否定的!
(1)如果处理点击事件的时候,事件被本层onTouchEvent()所消费(返回true),那么本层View 的拦截器会被忽略掉,本层无论是View还是Viewgroup,都会被当成一个View处理.
(2)若所有层级都没有处理点击事件,那么后续的所有事件将会直接在activity中处理,不再下发给内层的View(以及GroupView),也就是说如果activity #dispatchTouchEvent()返回false,直接调用activity#onTouchEvent,无论onTouchEvent 是否会处理消费.
二、拦截器(interceptTouchEvent())
1、Activity与非容器View没有拦截器.
2、处理任何事件返回true,则事件传递本层View的消费器(onTouchEvent()).
3、如果返回false,则向下传播,到内层View的dispatchTouchEvent(如果没有子View,与返回true同样效果,将事件传递本层View的消费器(onTouchEvent()).
三、消费器(onTouchEvent())
1、在处理点击事件时返回true,则事件直接结束,不再传递.
2、那么消费点击事件的那一层View(或viewgroup)在处理后面的其他事件的时候,返回true/false,都有什么区别呢?(不考虑这层View的内层View ,因为内层View未处理点击事件,已被系统忽略)
(1)在处理点击事件的时候,如果返回true,后续事件将会忽略除了Activity以及本层View之外的所有View的onTouchEvent(),也就是说,你不处理点击事件,或者点击事件被其他View所消费,那么与这个点击事件相关的后续滑动、抬起事件将会自动忽略你.只有Activity的onTouchEvent比较特殊一点点.
(2)为什么说Activity的onTouchEvent比较特殊,是因为 ,如果消费了点击事件的那一层View如果不消费后续的滑动、抬起事件,那么事件会直接传递到Activity#onTouchEvent中
那么我们就可以得出第四条
四、消费器(onTouchEvent()) 在处理移动、取消、抬起事件时返回true,则事件直接传递到Activity的消费器(onTouchEvent())----(无论是View还是ViewGroup,也无论中间还有多少层级,直接跨过到Activity).(注意不包括点击事件)
可能你也看出来了,消费器(onTouchEvent())在处理点击事件的时候,也扮演着一个拦截器的作用,消费点击事件的那一层View,将会变成后续事件可到达的最底层,这一层 View无论内部还有没有子View,事件都不会再去传递.
上面四点如果你看的有点儿懵懂,混乱,的话,可能你需要多点儿耐心,再看一遍,因为这是整个事件流程的核心部分,当然也可以先看后面的流程图,跟上文进行验证对比来理解,可能更容易一点:
2、完整流程图
上面这两个图片是对第一点“总结”当中的思维走向,流程图表达的方式是以满足逻辑走向为主,与上方的文字相结合来理解比较好懂一些.
若有不对的地方欢迎指正!