写自定义控件时,经常遇到事件冲突问题,之前事件分发问题零星的梳理过几遍,但奈何分发事件由于情况的多变,导致最后的结果种类太多,时间长了又没有印象了。又不能每次遇到问题就从源码梳理一遍,特此梳理一份全网最全的事件分发结果速查表

此处不对源码做讲解,只提供事件分发流程快速查询结果,便于在平时工作中能够快速定位

 

View事件分发机制速查表
标题

说明:

1、方形虚线框是对应控件的相关方法。如ViewGroup1、ViewGroup2、View可能分别为继承自RelativeLayout的MyRelativeLayout、继承自LinearLayout的MyLinearLayout、继承自ImageView的MyImageView三个控件;包含层次为ViewGoup1包含ViewGroup2包含View

2、认清方法位置。dispatchTouchEvent、interceptTouchEvent、onTouchEvent三个方法在自定义控件中重写,而onclick、ontouch在设置监听的位置如MainActivity中,注意:此处的onclick表示可点击,控件要可点击,要么是button这种,本身是clickable的,要么是RelativeLayout、ImageView这种本身不可点击,但在xml中可以设置clickable或者在代码中设置onclicklistener。

3、每个方法对事件的处理:1. true 消费,即此方法return true,表示事件到此处之后就结束了后面的箭头及流程都不会走了;2.箭头+false,即此方法return false;3.箭头+supper,即此方法返回supper.此方法;4.特殊情况,即onclick方法无返回值,那么不根据它的返回值判断是否消费,只要是设置了onclick方法,此方法就消费。上面的控件默认都未设置onclick

4、事件从左上角开始,如果不设置任何拦截消费,也不设置onclick消费,最后会回到右上角

5、View是没有interceptTouchEvent方法的,此处添加上是为了更好的和上面的类比

6、ontouch监听如果不设置,对流程无影响,箭头连起来即可

7、move、up事件原则:最短距离原则,即在没有特殊处理情况下,down事件被哪个控件消费,move、up事件就用最短距离走到该控件,如果是左侧的dispatchTouchEvent返回true,那move、up事件和down的路径是一样的,如果是右侧消费,那么就用最短距离走到该控件开始的回溯的地方,即走绿线,如ViewGroup2的onTouchEvent方法返回了true,那么down的流程 ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->interceptTouchEvent->View的dispatchTouchEvent->onTouch->onTouchEvent->ViewGoup2的onTouch->onTouchEvent,而move和up的流程 ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->ViewGoup2的onTouch->onTouchEvent

举例:

1.都不消费, ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->interceptTouchEvent->View的dispatchTouchEvent->onTouch->onTouchEvent->ViewGoup2的onTouch->onTouchEvent->ViewGoup1的onTouch->onTouchEvent->activity的onTouch ...  而图中没人消费,所以move、up按最短距离应该在activity的没有标出的虚无的绿线中,所以日志没有打印

2.在ViewGroup2中的dispatchTouchEvent中返回true进行消费,事件流程 ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent,结束,后续的move和up事件流程相同

3.在ViewGroup2中的dispatchTouchEvent中返回false,事件流程 ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->ViewGoup1的onTouch->onTouchEvent->activity的ontouch,后续的move和up事件流程相同

4.给ViewGroup2设置onclicklistener事件或者在xml中给它添加可点击设置事件流程:

down事件流程 ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->interceptTouchEvent->View的dispatchTouchEvent->onTouch->onTouchEvent->ViewGoup2的onTouch->onTouchEvent结束,但是此时onclick中不会打印,它还要等待up才会回掉到onclick;

move事件流程ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的onTouch->onTouchEvent

up事件流程ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的onTouch->onTouchEvent->onClick

 

另类思考:

以上的讨论都是基于同一个方法同一种返回值的情况,但是,也有特殊情况,dispatchTouchEvent、interceptTouchEvent、onTouch、onTouchEvent的方法中都有MotionEvent事件,如果把每个事件又单独分开做不同的返回值,比如:ViewGroup2的touchEvent中返回true,同时在ViewGroup2的dispatchTouchEvent中对event进行分类处理,down时返回supper,而move和up时返回true或false,那么情况会怎么样呢?先说答案:还是参照总图,true时,move和up流程ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent 结束;重点来了,false时,move和up流程ViewGroup1的dispatchTouchEvent->interceptTouchEvent->ViewGoup2的dispatchTouchEvent 结束,看到没,和down的不一样!!!没有按照图形在false时把move给父控件的onTouch,为什么这么设计?想想就明白了,父控件down都没有,怎么能move和up?  所以,最后总结,不推荐这么做,实际业务也难找到这种情况,并且这种情况对应的种类太多dispatchTouchEvent、interceptTouchEvent、onTouch、onTouchEvent中都可以对event的down、move、up三种进行不同操作,排列组合一下,81种。。。所以遇上这种场景再通过代码调试才是明智之举

 

附录:

activity中布局setContentView为 RelativeLayout,RelativeLayout中包含MyRelativeLayout,MyRelativeLayout中包含MyImageView,全部不消费,事件分发日志:

View事件分发机制速查表

相关文章: