您的位置:首页 > 移动开发 > Android开发

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

2016-07-20 11:29 483 查看
事件分发机制

一.点击事件传播路径
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的大小范围内)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: