在Android开发中,事件分发机制是Android比较重要的知识体系。了解和熟悉整套分发机制,将有助于你更好地分析各种点击和滑动失败的问题,更好地扩展控件的事件功能和自定义控件的开发。同时,事件分发机制也是Android面试必问的考点之一。如果你能现场画出下面的一些事件分布图,肯定会加分不少。废话不多说,总结一下:事件分发机制很重要。Android事件分发流程网上有很多关于Android事件分发机制的博文,但是很多都是写个demo贴出输出日志或者分析源码,然后就是一堆评论和说明。仔细看的话,一定会收获不少。但是真的很难解释和记住整个过程。我曾经尽力记住整个过程,但我忘记了一段时间。***我觉得把这种问题和事件流的方向分析清楚,用图说明会清楚很多。我将根据下面的事件图片分发它。流程图说明了在不同函数返回值不同的情况下,用户点击后事件的最终走向。图1.注:仔细看,图片分为3层。从上到下分别是Activity、ViewGroup、View事件。从左上角的白色箭头开始,使用Activity的dispatchTouchEvent来分发箭头。(returntrue,returnfalse,returnsuper.xxxxx(),super的意思是调用父类实现。在dispatchTouchEvent和onTouchEvent的方框中有个词[true—>consumption],意思是如果方法返回true,那么就是说这个事件会在此时被消费掉,不会再继续传递到其他地方,事件就终止了。目前图中所有的事件都是针对ACTION_DOWN的,我们分析下ACTION_MOVE和ACTION_UP.无论Activity的dispatchTouchEvent返回什么,都会调用ViewGroup的dispatchTouchEvent(自己看源码)仔细看全图,我们可以得出几个关于事件流向的结论(希望读者会专心看下面的图1,多看几遍,脑子里会有更清晰的概念。)1.如果事件没有被打断,整个事件流是一个U型图,我们看这张图,A并且我们可能更好地理解U形图的含义。图2.那么如果我们不重写或者改变控件中方法的返回值,而是直接使用super调用父类的默认实现,那么整个事件流程应该是从Activity—>ViewGroup—>View从上到下调用??dispatchTouchEvent方法,直到叶子节点(View),然后从下到上通过View—>ViewGroup—>Activity调用onTouchEvent方法。2.一旦dispatchTouchEvent和onTouchEvent返回true,事件将停止传递(到达终点)(没有人可以再次收到此事件)。看下图,只要不传递returntrue事件,我们常说的returntrue事件已经被消费了,意思是事件来到这里就是终点,不会传递下去,并且没有人可以再次收到此事件。图3.3,当dispatchTouchEvent和onTouchEvent返回false时,事件被传回给父控件的onTouchEvent处理。图4.查看上图中的深蓝色线。对于返回false的情况,事件传递给父控件onTouchEvent处理。dispatchTouchEvent返回false的意思应该是:事件停止向子View传递分发,同时开始回溯到父控件(父控件的onTouchEvent开始自下而上回传,直到某个onTouchEventreturntrue),事件分发机制就像递归,returnfalse的意思是停止递归,开始回溯。对于onTouchEventreturnfalse比较简单,就是不消费事件,让事件继续沿着父控件的方向从下往上流。4、dispatchTouchEvent、onTouchEvent、onInterceptTouchEventViewGroup和View这几个方法的默认实现是让整个事件安装U型完成,所以returnsuper.xxxxxx()会让事件按照U型方向完成整个事件流程Path),中间不做任何改动,不回溯,不终止,走到每一个环节。Paste_Image.png所以如果你看到方法returnsuper.xxxxx(),那么事件的下一个方向就是去U型下一个目标。记住上图,你就可以快速判断下一个方向是哪个控件是哪个功能。5.onInterceptTouchEvent的作用图5.Intercept的意思是拦截。每次分发每个ViewGroup时,询问拦截器是否拦截(即询问自己是否要自己处理这个事件)如果要进行处理,在onInterceptTouchEvent方法中返回true将交给自己的onTouchEvent进行加工。如果没有被拦截,它会继续向下传递给子控件。默认不会拦截,因为子View也需要这个事件,所以onInterceptTouchEvent拦截器returnsuper.onInterceptTouchEvent()和returnfalse一样,不会拦截,事件会继续传给子视图的dispatchTouchEvent。6、ViewGroup和View的dispatchTouchEvent方法返回super.dispatchTouchEvent()时的事件流向。图6首先看ViewGroup的dispatchTouchEvent。前面说的returntrue就是最后的投递。returnfalse就是回到父View的onTouchEvent,那么ViewGroup如何通过dispatchTouchEvent方法把事件分发给自己的onTouchEvent呢?returntrue和false是不行的,所以事件只能被Interceptor拦截到自己的onTouchEvent,所以ViewGroup的dispatchTouchEvent方法的超默认实现是调用onInterceptTouchEvent,记住这个。那么当View的dispatchTouchEvent返回super.dispatchTouchEvent()时,事件会传递到哪里呢?不幸的是,View没有拦截器。但是同样的道理returntrue就是结束。returnfalse是父类的onTouchEvent,如何把事件分发给自己的onTouchEvent处理,那只能返回super.dispatchTouchEvent,View类的dispatchTouchEvent()方法默认实现是帮你调用View自己的onTouchEvent方法。说了这么多,也不知道说清楚没有。这里总结一下:对于dispatchTouchEvent,onTouchEvent,returntrue就是事件传递结束。returnfalse就是回溯到父View的onTouchEvent方法。ViewGroup想把自己分发给自己的onTouchEvent,需要拦截器onInterceptTouchEvent方法返回true来拦截事件。ViewGroup的拦截器onInterceptTouchEvent默认是不拦截的,所以returnsuper.onInterceptTouchEvent()=returnfalse;View没有拦截器,为了让View分发事件给自己的onTouchEvent,View的dispatchTouchEvent的默认实现(super)是将事件分发给自己的onTouchEvent。ViewGroup和View的dispatchTouchEvent是做事件分发的,所以这个事件可能分发到的四个target注意:——>后者代表事件target需要做什么。1.自用,结束发货。————>返回真;2、处理自己的onTouchEvent————>调用super.dispatchTouchEvent(),系统会默认调用onInterceptTouchEvent,当onInterceptTouchEvent返回true时,会将事件分发给自己的onTouchEvent处理。3.传递给子View-->调用super.dispatchTouchEvent()默认实现会调用onInterceptTouchEvent如果onInterceptTouchEvent返回false,事件就会传递给子类。4、没有传递给子View,事件终止向下传递,事件开始回溯,从父View的onTouchEvent开始,事件自下而上返回,执行各控件的onTouchEvent——>返回假;注意:由于View没有childView,所以不需要onInterceptTouchEvent来控制事件是传递给childView还是拦截,所以当View的事件分发调用super.dispatchTouchEvent()时,事件被传递默认到自己的onTouchEvent处理(相当于拦截),View的事件分发没有上述4个目标的第3点。ViewGroup和View的onTouchEvent方法是做事件处理的,所以这个事件只能有两种处理方式:1、自己消费,事件结束,不再传递给任何人——>返回true;2、继续从下往上上传,不消费事件,这样父View也能收到这个事件——>returnfalse;View的默认实现是不消费的。所以超级==假。ViewGroup的onInterceptTouchEvent方法对于事件有两种情况:1、拦截它,为自己的onTouchEvent处理—>returntrue;2、不拦截,把事件传给子View-->returnfalse,ViewGroup默认不拦截,所以super==false;关于ACTION_MOVE和ACTION_UP,上面的解释都是针对ACTION_DOWN事件的传递。ACTION_MOVE和ACTION_UP在传递过程中与ACTION_DOWN不同。你在执行ACTION_DOWN的时候返回false,后面一系列的其他动作就不会再执行了。简单的说,dispatchTouchEvent在派发事件时,只有之前的事件(比如ACTION_DOWN)返回true,才会接收到ACTION_MOVE和ACTION_UP事件。很多博主都具体说过这句话,但是具体是什么意思呢?下面我们来看看具体的分析。上面说了,如果事件没有被打断,它会继续向下传递到叶子层(View),然后又不断传递回Activity。dispatchTouchEvent和onTouchEvent可以通过returntrue和结束事件传递来消费事件,而onInterceptTouchEvent是不能消费事件的。相当于一个分叉,起到分流分流的作用。将调用哪些函数ACTION_MOVE和ACTION_UP。前面说过,不是哪个函数接收到ACTION_DOWN,它会接收到ACTION_MOVE等后续事件。下面通过几张图来看看ACTION_MOVE和ACTION_UP事件在不同场景下的具体变化趋势,总结规律。1、ViewGroup1的dispatchTouchEvent方法返回true,消费该事件。ACTION_DOWN事件从(Activity的dispatchTouchEvent)————>(ViewGroup1的dispatchTouchEvent)传递过来,事件被消费(红色箭头代码ACTION_DOWN事件流向)。//打印logActivity|dispatchTouchEvent-->ACTION_DOWNViewGroup1|dispatchTouchEvent-->ACTION_DOWN---->这个场景下ACTION_MOVE和ACTION_UP会发生什么?看下面日志Activity|dispatchTouchEvent-->ACTION_MOVEViewGroup1|dispatchTouchEvent-->ACTION_MOVE--TouchEventActivity|dispatchTouchEvent-->ACTION_UPViewGroup1|dispatchTouchEvent-->ACTION_UP----下图中红色箭头代表ACTION_DOWN事件流向,蓝色箭头代表ACTION_MOVE和ACTION_UP事件流向到粘贴图像。png2,我们在ViewGroup2的dispatchTouchEvent中返回true来消费这个事件Activity|dispatchTouchEvent-->ACTION_DOWNViewGroup1|dispatchTouchEvent-->ACTION_DOWNViewGroup1|onInterceptTouchEvent-->ACTION_DOWNViewGroup2|dispatchTouchEvent-->ACTION_DOWN---->ConsumeActivity|dispatchTouchEvent-->ACTION_MOVEViewGroup1|dispatchTouchEvent-->ACTION_MOVEViewGroup1|onInterceptTouchEvent-->ACTION_MOVEViewGroup2|dispatchTouchEvent-->ACTION_MOVE----TouchEventActivity|dispatchTouchEvent-->ACTION_UPViewGroup1|dispatchTouchEvent-->ACTION_UPViewGroup1|onInterceptTouchEvent-->ACTION_UPViewGroup2|dispatchTouchEvent-->ACTION_UP----红色箭头代表ACTION_DOWN事件流向,蓝色箭头代表ACTION_MOVE和ACTION_UP事件流向Paste_Image.png3。我们在View的dispatchTouchEvent中返回true来消费这个事件我就不画图了,效果和ViewGroup2中的dispatchTouchEvent返回true类似,同样的dispatchTouchEvent函数接收ACTION_DOWN可以接收ACTION_MOVE和ACTION_UP,所以我们基本可以得出结论如果某个控件的dispatchTouchEvent返回true的消费结束事件,那么接收ACTION_DOWN的函数也可以接收ACTION_MOVE和ACTION_UP。4.我们在View的onTouchEvent返回true的时候消费这个事件。红色箭头表示ACTION_DOWN事件的流程。蓝色箭头表示ACTION_MOVE和ACTION_UP事件的流程。5、我们在ViewGroup2的onTouchEvent中返回true来消费这个事件,红色箭头代表ACTION_DOWN事件的流向蓝色箭头代表ACTION_MOVE和ACTION_UP事件的流向。6、我们在ViewGroup1的onTouchEvent中返回true来消费这个事件。红色箭头表示ACTION_DOWN事件的流向。蓝色箭头表示ACTION_MOVE和ACTION_UP事件Paste_Image的流向。PNG7。当Activity的onTouchEvent返回true时,我们使用此事件。红色箭头表示ACTION_DOWN事件的流向。蓝色箭头表示ACTION_MOVE和ACTION_UP事件的流向。8、我们在View的dispatchTouchEvent返回false,Activity的onTouchEvent返回true来消费这次事件的红色箭头代表ACTION_DOWN事件的流向。蓝色箭头表示ACTION_MOVE和ACTION_UP事件的流向。9、我们在View的dispatchTouchEvent中返回false,ViewGroup1的onTouchEvent返回true来消费这个事件。红色箭头代表ACTION_DOWN事件流向蓝色箭头代表ACTION_MOVE和ACTION_UP事件流向10、我们在View的dispatchTouchEvent中返回false,在ViewGroup的onTouchEvent中返回true来消费这个事件。红色箭头表示ACTION_DOWN事件的流程。蓝色箭头表示ACTION_MOVE和ACTION_UP事件的流程11、我们在ViewGroup2的dispatchTouchEvent中返回false,在ViewGroup1的onTouchEvent中返回true来消费这个事件。红色箭头代表ACTION_DOWN事件的流程,蓝色箭头代表ACTION_MOVE和ACTION_UP事件12的流向我们通过在ViewGroup2的onInterceptTouchEvent中返回true来拦截这个事件,在ViewGroup1的onTouchEvent中返回true来消费这个事件。红色箭头代表ACTION_DOWN事件的流向蓝色箭头代表ACTION_MOVE和ACTION_UP事件的流向一下子画了很多图,还有几种情况就不画了。我相信你可以看到规则。对于onTouchEvent中消费事件的情况:其中View的onTouchEvent返回true,那么ACTION_MOVE和ACTION_UP的事件是从上到下下载到这个View之后,就不再向下传递,而是直接传递给自己的onTouchEvent并结束事件传递过程。ACTION_MOVE和ACTION_UP总结:ACTION_DOWN事件是在哪个控件中消费的(返回true),那么ACTION_MOVE和ACTION_UP会从上到下分发(通过dispatchTouchEvent),只会传递给这个控件,不会继续往下传递,如果在dispatchTouchEvent中消费了ACTION_DOWN事件,则事件将停止传递到这里,如果在onTouchEvent中消费了ACTION_DOWN事件,则将ACTION_MOVE或ACTION_UP事件传递给控件的onTouchEvent处理,传递结束。
