android事件分发机制解析(配流程图)

事件分发机制
一.点击事件传播路径
1.点击事件TouchEvent最先是到达Activity的,然后传给Activity对应的window,再传给DecorView,再传给id为content的ViewGroup,即我们通过setContentView设置的ViewGroup,以此到最后的view。我们编程所能控制的由Activity,ViewGroup和View。


2.要把点击事件传给一个View或ViewGroup,要调用其dispatchTouchEvent(),要判断该View或ViewGroup是否拦截,要调用其onInterceptTouchEvent(),要判断该View或ViewGroup是否消耗,要调用其onTouchEvent()。子view没有onInterceptTouchEvent(),所以传给在子view的点击事件都是直接判断是否要消耗。当一个事件被消耗了就会消失掉。


 
3.自定义的ViewGroup和View默认都是不拦截点击事件的,ViewGroup决定拦截与否是通过onInterceptTouchEvent()的返回值决定的;ViewGroup决定消耗事件与否是通过onTouchEvent()决定的。View因为没有onInterceptTouchEvent(),所有决定拦截与否跟消耗与否是通过onTouchEvent()的返回值决定的,true表示拦截,false表示不拦截。注意分清拦截和消耗。
ViewGroup的onInterceptTouchEvent()如下




4.在子View的dispatchTouchEvent()内部有这样一段代码


其逻辑是,如果View设置了onTouchListener,则其onTouchListener的onTouch()方法会被调用。如果该方法返回false,则会调用onTouchEvent(),但是如果该方法返回true,则onTouchEvent()方法不会被调用,且这种情况属于自view消耗了点击事件。而我们平时的setOnClickListener()设置的OnClickListener是在onTouchEvent()里被执行的,并且如果我们没有重写onTouchEvent()的话,onTouchEvent()会返回true。






二.具体情况分析
1.当ViewGroup和View都不拦截不消耗点击事件ACTION_DOWN时流程如下


并且之后的ACTION_MOVE和ACTION_UP都不会再传给ViewGroup和VIew,而是直接交给Activity的onTouchEvent()处理
2,若ViewGroup不拦截,在view也不消耗,然当事件再次来到ViewGroup的onTouchEvent()时,如果ViewGroup决定要消耗掉该ACTION_DOWN,则以后该TouchEvent的ACTION_MOVE和ACTION_UP都会传到该ViewGroup,并且不会调用其onInterceptTouchEvent()


3.当ViewGroup的onInterceptTouchEvent()拦截了ACTION_DOWN时,点击事件不再传给子view,这时候会调用ViewGroup的onTouchEvent()判断是否要消耗ACTION_DOWN,如果不消耗,则会调用Activity的onTouchEvent(),并且以后该TouchEvent系列的ACTION_MOVE和ACTION_UP都不会再传给ViewGroup即其以下的子View。


如果消耗,则以后该TouchEvent系列的ACTION_MOVE和ACTION_UP都会传给该ViewGroup(当不会传给其子view),并且不会再调用该ViewGroup的onInterceptTouchEvent()。




4.对于ACTION_DOWN,当ViewGroup不拦截,子view决定消耗。那么该事件之后的ACTION_MOVE和ACTION_UP都会正常传进来,即先经过ViewGroup的dispatchTouchEvent(),再到onInterceptTouchEvent(),接着到子view的onTouchEvent(),这时即使不被View和ViewGroup消耗,同一事件体系的ACTION_MOVE和ACTION_UP都会正常传进来ViewGroup和View的。注意,这时当子view不消耗事件时,事件不会传给ViewGroup的onTouchEvent(),而是直接交给Activity


5.当ACTION_DOWN到ViewGroup时,如果ViewGroup不拦截,事件传给子view,如果子view消耗了,但当第一个ACTION_MOVE到ViewGroup时,ViewGroup拦截,这时,这个ACTION_MOVE会传给子View,触发子view的onTouchEvent,不过这时ACTION_MOVE变为ACTION_CANCEL,如果子view消耗了,则该ACTION_CANCEL消失,如果子View不消耗,则该ACTION_CANCEL传给ACtivity的onTouchEvent()。然而,不管子View消耗不消耗ACTION_CANCEL,第二个开始的ACTION_MOVE和ACTION_UP都不会再传到子view了,二是得到ViewGroup的dispatchTouchEvent(),再直接传给ViewGroup的onTouchEvent()ViewGroup决定消耗则消耗,不消耗则回传给Activity。


6.当ViewGroup不拦截ACTION_DOWN和ACTION_MOVE,但子view拦截了。然后ViewGroup拦截ACTION_UP,这时,ACTION_UP会以ACTION_CANCEL形式传给子view,子View处理ACTION_CANCEL则事件消失,不处理则传回给Activity。


三.Android内置View分析
自定义的View默认是不消耗点击事件的。而Android自带的View则不一定,要该View的clickable和longClickable同时为false才不消耗点击事件,主要有一个不为false,则要消耗点击事件。TextView默认是不消耗点击事件的,除非为它设置了onTouchListener或onClickListener。Button则是消耗点击事件的,除非把他设置为不可点击。(严格来说,事件被判断为onClick必须是ACTION_DOWN,ACTION_MOVE,ATION_UP都发生在View的大小范围内)。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值