Android View的事件分发机制Word下载.docx
《Android View的事件分发机制Word下载.docx》由会员分享,可在线阅读,更多相关《Android View的事件分发机制Word下载.docx(14页珍藏版)》请在冰豆网上搜索。
当一个点击事件(MotionEvent)产生后,事件最先传递给当前的界面(Activity),这点是很好理解的。
Activity再将事件传递给窗口(Window),然后Window将事件传递给顶级View(DecorView)。
此时,事件已经到达了View了。
之后顶级View就会按照事件分发机制去分发事件。
具体是这样的:
对于一个根ViewGroup来说,点击事件产生后,首先会传递给它,这时它的dispatchTouchEvent方法就会被调用,如果这个ViewGroup的onInterceptTouchEvent方法返回true就表示它要拦截当前事件,接着事件就会交给这个ViewGroup处理,即它的onTouchEvent方法就会被调用。
如果这个ViewGroup的onInterceptTouchEvent方法返回false,就表示它不拦截当前事件,这时当前事件就会继续传递给它的子元素,接着子元素的dispatchTouchEvent方法就会被调用,如此反复直到事件被最终处理。
如果一个View的onTouchEvent方法返回false,那么它的父容器的onTouchEvent方法会被调用,如果它的父容器的onTouchEvent方法还是返回false,那就继续往上抛,当所有的元素都不处理这个事件,那么这个事件会最终传递给Activity处理,即Activity的onTouchEvent方法会被调用。
好了,现在已经铺垫了基础,那么接下来就从源码的角度来分析事件分发机制。
当然是从Activity的dispatchTouchEvent方法开始分析。
源码如下:
publicbooleandispatchTouchEvent(MotionEventev){
if(ev.getAction()==MotionEvent.ACTION_DOWN){
onUserInteraction();
}
if(getWindow().superDispatchTouchEvent(ev)){
returntrue;
returnonTouchEvent(ev);
}
如果当前事件是down的话,就调用onUserInteraction方法,onUserInteraction是一个空方法,我们可以暂时不搭理。
然后调用getWindow方法获取到当前Activity关联的Window,Window再调用superDispatchTouchEvent方法将事件传入进行分发。
如果superDispatchTouchEvent方法返回true的话,view已经处理了事件。
整个事件循环结束。
如果返回false,没有view处理这个事件。
事件往上抛,那就Activity自己处理了,即Activity的onTouchEvent方法会被调用。
因为想要知道事件的整个分发过程,现在关注的是Window的superDispatchTouchEvent方法,那么就跟进去看看:
publicabstractbooleansuperDispatchTouchEvent(MotionEventevent);
Window是一个抽象类,superDispatchTouchEvent是一个抽象的方法,那么我们必须要找到window的实现类才行,可是茫茫人海怎么找呢?
看到window类的说明就明白了
*<
p>
Theonlyexistingimplementationofthisabstractclassis
*android.view.PhoneWindow,whichyoushouldinstantiatewhenneedinga
*Window.
*/
publicabstractclassWindow
意思是Window存在唯一的实现是android.view.PhoneWindow
那么PhoneWindow里的superDispatchTouchEvent方法就是我们要找的信息,如下:
@Override
publicbooleansuperDispatchTouchEvent(MotionEventevent){
returnmDecor.superDispatchTouchEvent(event);
直接将事件传递给了DecorView。
这时事件已经是到达View了哦。
那么跟进DecorView的superDispatchTouchEvent方法看看,如下:
returnsuper.dispatchTouchEvent(event);
内部调用了父类的dispatchTouchEvent方法,那么DecorView的父类是什么呢?
DecorView肯定是View的,那么刚才开篇提到,我们通过setContentView设置的View,是DecorView的子View。
那么更加准确的说DecorView是一个ViewGroup。
privatefinalclassDecorViewextendsFrameLayoutimplementsRootViewSurfaceTaker
可以看到DecorView是继承自FrameLayout,FrameLayout是ViewGroup,也就是说DecorView是一个ViewGroup。
那么现在只需要关注ViewGroup的dispatchTouchEvent方法。
继续前进
ViewGroup的事件分发
ViewGroup的dispatchTouchEvent方法如下:
//代码省略
//Checkforinterception.
finalbooleanintercepted;
if(actionMasked==MotionEvent.ACTION_DOWN
||mFirstTouchTarget!
=null){
finalbooleandisallowIntercept=(mGroupFlags&
FLAG_DISALLOW_INTERCEPT)!
=0;
if(!
disallowIntercept){
intercepted=onInterceptTouchEvent(ev);
ev.setAction(action);
//restoreactionincaseitwaschanged
}else{
intercepted=false;
//Therearenotouchtargetsandthisactionisnotaninitialdown
//sothisviewgroupcontinuestointercepttouches.
intercepted=true;
canceled&
&
!
intercepted){
finalintchildrenCount=mChildrenCount;
if(newTouchTarget==null&
childrenCount!
=0){
finalfloatx=ev.getX(actionIndex);
finalfloaty=ev.getY(actionIndex);
//Findachildthatcanreceivetheevent.
//Scanchildrenfromfronttoback.
finalArrayList<
View>
preorderedList=buildOrderedChildList();
finalbooleancustomOrder=preorderedList==null
&
isChildrenDrawingOrderEnabled();
finalView[]children=mChildren;
for(inti=childrenCount-1;
i>
i--){
finalintchildIndex=customOrder
?
getChildDrawingOrder(childrenCount,i):
i;
finalViewchild=(preorderedList==null)
children[childIndex]:
preorderedList.get(childIndex);
//Ifthereisaviewthathasaccessibilityfocuswewantit
//togettheeventfirstandifnothandledwewillperforma
//normaldispatch.Wemaydoadoubleiterationbutthisis
//safergiventhetimeframe.
if(childWithAccessibilityFocus!
=child){
continue;
childWithAccessibilityFocus=null;
i=childrenCount-1;
canViewReceivePointerEvents(child)
||!
isTransformedTouchPointInView(x,y,child,null)){
ev.setTargetAccessibilityFocus(false);
newTouchTarget=getTouchTarget(child);
if(newTouchTarget!
//Childisalreadyreceivingtouchwithinitsbounds.