天天看点

带你根据源码了解View的事件触发流程,主要讲解为什么子View返回true,ViewGroup就无法接收到事件的过程

转载请标明出处!http://blog.csdn.net/sahadev_/article/details/23839039 ,当然一般也没人转载。。。

一直想彻底了解View的事件分发过程,在网上也看了很多大神的博客,但是总有一些东西不是很明白,于是自己就根据源码画了一个流程草图,思路总算是清晰了。

文章分为View和ViewGroup两部分介绍,首先来讲讲View的事件分发:

打开View的源码,顺着onTouch方法向上找到dispatchPointerEvent(MotionEvent event)的这个方法,在View中再没有其它地方调用它,估计事件就是从这里传过来的吧。

来贴一下这个方法的源码:

看到在这个方法中调用了dispatchTouchEvent的这个方法,dispatchTouchEven()暂时没找到它的相关说明,权当它返回了true,进入dispatchTouchEvent方法:

可以看到在这个方法中调用了onTouchEvent(Event),所以可知onTouchEvent(event)是由dispatchTouchEvent触发的。如果有人对onFilterTouchEventForSecurity这方法有疑问,API中是这么解释的:True if the event should be dispatched, false if the event should be dropped.这句话就不用翻译了吧,相信大家都懂。

如果onTouchEvent返回了true,那么dispatchTouchEvent的返回值也为true. 对于dispatchTouchEvent的返回值说明是这么解释的:True if the event was handled by the view, false otherwise. 如果返回true,说明这个事件就被当前的这个View消费掉了,这里的返回值大家一定要清楚,一会在ViewGroup的说明中需要对这块很熟悉。

接下来说一说ViewGroup的事件分发方法:

ViewGroup的事件处理相对View相对有些复杂,ViewGroup继承于View,在View中dispatchTouchEvent是由dispatchPointerEvent触发的,所以ViewGroup也是由dispatchPointerEvent触发的,这里不重要,接着看ViewGroup的dispatchTouchEvent的源代码:

ViewGroup的dispatchTouchEvent的方法有些长,在代码中可以看到,ViewGroup将View的该方法彻底重写了,没有很明显的看到super.dispatchTouchEvent的字样,也就是说还没有着急把事件交给View去处理。

前几行和View都差不错,往下看

在第5行中调用了onInterceptTouchEvent(ev);该方法表示当按下事件触发的时候是否要拦截本次事件,这个方法的源码是这样的:

如果不对它进行重写的话,它总是返回false,也就是说intercepted的值恒为false,接着往下看,看到 if (!canceled && !intercepted) {这一行的时候,由于intercepted为false,所以事件可以进入if内执行,接着往下看:

看到这段代码中dispatchTransformedTouchEvent的这个方法开始对ViewGroup的子View进行事件传递了:

该方法的最终返回值是布尔值,意思为是否被处理了,请看这里:

这里开始对子View进行事件传递,调用子View的dispatchTouchEvent的方法,如果被子View消费掉了本次事件,dispatchTransformedTouchEvent就返回true,再回到那个循环:

请注意这个方法:

这个方法中的代码是这样的:

注意将mFirstTouchTarget赋了值,不再是null,先记住这里,待会有用。

好了,子View循环完成之后,代码会执行到这里:

注意到刚刚mFirstTouchTarget被赋了值,不再是null,不为null,就不会执行if中的语句,if中的语句都做了些什么呢?

注意第3个参数是Null,咱们再返回到dispatchTransformedTouchEvent中(刚才已经贴过方法内的代码):

该方法内有3处super.dispatchTouchEvent(event);因为刚才mFirstTouchTarget的值不为null,所以没有进入if,所以ViewGroup没法去调用super.dispatchTouchEvent(event);所以当子View把事件消费完成之后,ViewGroup就无法接收到onTouchEvent事件,这就是为什么子View返回true,ViewGroup就无法处理的原因。

事件传递到这里也就讲完了,不知道大家有没有听明白,如果有什么疑问可以在下面留言,欢迎转载!

继续阅读