Android进阶Android事件分发机制之dispatchTouchEventonInterceptTouchEventonTouchEvent.docx
- 文档编号:28869607
- 上传时间:2023-07-20
- 格式:DOCX
- 页数:17
- 大小:182.86KB
Android进阶Android事件分发机制之dispatchTouchEventonInterceptTouchEventonTouchEvent.docx
《Android进阶Android事件分发机制之dispatchTouchEventonInterceptTouchEventonTouchEvent.docx》由会员分享,可在线阅读,更多相关《Android进阶Android事件分发机制之dispatchTouchEventonInterceptTouchEventonTouchEvent.docx(17页珍藏版)》请在冰豆网上搜索。
Android进阶Android事件分发机制之dispatchTouchEventonInterceptTouchEventonTouchEvent
Android进阶——Android事件分发机制之dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent
前言
Android事件分发机制可以说是我们Android工程师面试题中的必考题,弄懂它的原理是我们避不开的任务,所以长痛不如短痛,花点时间干掉他,废话不多说,开车啦
Android事件分发机制的简介
Android事件分发机制的发生在View与View之间或者ViewGroup与View之间具有镶嵌的视图上,而且视图上必须为点击可用。
当一个点击事件产生后,它的传递过程遵循如下顺序:
Activity->Window->View,即事件先传递给Activity,再到Window,再到顶级View,才开始我们的事件分发
Android事件分发机制的相关概念
Android事件分发机制主要由三个重要的方法共同完成的
dispatchTouchEvent:
用于进行点击事件的分发
onInterceptTouchEvent:
用于进行点击事件的拦截
onTouchEvent:
用于处理点击事件
这里需要注意的是View中是没有onInterceptTouchEvent()方法的
Android事件分发机制的分发例子
这里以两个ViewGroup嵌套View来演示,下面是演示图
一、MyView
继承View并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent,前面已经说了View是没有onInterceptTouchEvent方法的
publicclassMyViewextendsView{
publicMyView(Contextcontext){
super(context);
}
publicMyView(Contextcontext,AttributeSetattrs,intdefStyleAttr){
super(context,attrs,defStyleAttr);
}
publicMyView(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
@Override
publicbooleandispatchTouchEvent(MotionEventevent){
System.out.println("MyViewdispatchTouchEvent");
returnsuper.dispatchTouchEvent(event);
}
@Override
publicbooleanonTouchEvent(MotionEventevent){
System.out.println("MyViewonTouchEvent");
returnsuper.onTouchEvent(event);
}
}
二、MyViewGroup01和MyViewGroup02
MyViewGroup01和MyViewGroup02是一样的代码,这里以01为例,继承ViewGroup并覆写其三个构造方法,覆写dispatchTouchEvent和onTouchEvent和onInterceptTouchEvent方法
publicclassMyViewGroup01extendsLinearLayout{
publicMyViewGroup01(Contextcontext){
super(context);
}
publicMyViewGroup01(Contextcontext,AttributeSetattrs,intdefStyleAttr){
super(context,attrs,defStyleAttr);
}
publicMyViewGroup01(Contextcontext,AttributeSetattrs){
super(context,attrs);
}
@Override
publicbooleandispatchTouchEvent(MotionEventev){
System.out.println("MyViewGroup01dispatchTouchEvent");
returnsuper.dispatchTouchEvent(ev);
}
@Override
publicbooleanonInterceptTouchEvent(MotionEventev){
System.out.println("MyViewGroup01onInterceptTouchEvent");
returnsuper.onInterceptTouchEvent(ev);
}
@Override
publicbooleanonTouchEvent(MotionEventevent){
System.out.println("MyViewGroup01onTouchEvent");
returnsuper.onTouchEvent(event);
}
}
三、MyView和MyViewGroup布局文件
这里以ViewGroup和Group嵌套,由上面可以知道事件最后分配到布局的顶级View,这里的顶级View是MyViewGroup02,然后开始事件的传递
xmlversion="1.0"encoding="utf-8"?
>
android=" android: layout_width="200dp" android: layout_height="200dp" android: background="#0f0"> android: layout_width="100dp" android: layout_height="100dp" android: background="#f00"> android: layout_width="50dp" android: layout_height="50dp" android: background="#00f"/> 四、分析事件传递 点击MyView(即蓝色部分): 其事件会从顶级View(MyViewGroup02)往下分发,而事件的分发过程中分为两步骤 分发过程 处理过程 其正常的分发事件结果为 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent MyViewGroup01onInterceptTouchEvent MyViewdispatchTouchEvent //处理过程 MyViewonTouchEvent MyViewGroup01onTouchEvent MyViewGroup02onTouchEvent 1、dispatchTouchEvent(分发事件) 如果在MyViewGroup01的dispatchTouchEvent方法中返回true,表示需要在MyViewGroup01消费了整个事件,即不会再分发,也不会再处理。 dispatchTouchEvent方法中返回true的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent 如果在MyViewGroup01的dispatchTouchEvent方法中返回false,表示在MyViewGroup01点击事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费。 dispatchTouchEvent方法中返回false的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent //处理过程 MyViewGroup02onTouchEvent 2、onInterceptTouchEvent(拦截事件) 如果在MyViewGroup01的onInterceptTouchEvent方法中返回true,表示需要在MyViewGroup01拦截这个点击事件,不再继续往下分发,即MyView不再执行dispatchTouchEvent方法。 但是只是分发结束了而已,接着开始处理事件。 下面是onInterceptTouchEvent方法中返回true的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent MyViewGroup01onInterceptTouchEvent //处理过程 MyViewGroup01onTouchEvent MyViewGroup02onTouchEvent 如果在MyViewGroup01的onInterceptTouchEvent方法中返回false,表示需要在MyViewGroup01不会拦截这个点击事件,继续往下分发。 下面是onInterceptTouchEvent方法中返回false的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent MyViewGroup01onInterceptTouchEvent MyViewdispatchTouchEvent //处理过程 MyViewonTouchEvent MyViewGroup01onTouchEvent MyViewGroup02onTouchEvent 3、onTouchEvent(消费事件) 如果MyViewGroup01的onTouchEvent方法中返回true,表示MyViewGroup01可以将该事件直接消费掉了,即分发结束后,处理事件的时候,直接处理到MyViewGroup01就可以结束了。 下面是onTouchEvent方法中返回true的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent MyViewGroup01onInterceptTouchEvent MyViewdispatchTouchEvent //处理过程 MyViewonTouchEvent MyViewGroup01onTouchEvent 如果MyViewGroup01的onTouchEvent方法中返回false,表示MyViewGroup01不可以将该事件直接消费掉,即事件继续往上处理。 下面是onTouchEvent方法中返回false的打印信息 //分发过程 MyViewGroup02dispatchTouchEvent MyViewGroup02onInterceptTouchEvent MyViewGroup01dispatchTouchEvent MyViewGroup01onInterceptTouchEvent MyViewdispatchTouchEvent //处理过程 MyViewonTouchEvent MyViewGroup01onTouchEvent MyViewGroup02onTouchEvent 总结起来: dispatchTouchEvent returntrue: 表示该View内部消化掉了所有事件 returnfalse: 表示事件在本层不再继续进行分发,并交由上层控件的onTouchEvent方法进行消费 returnsuper.dispatchTouchEvent(ev): 默认事件将分发给本层的事件拦截onInterceptTouchEvent方法进行处理 onInterceptTouchEvent returntrue: 表示将事件进行拦截,并将拦截到的事件交由本层控件的onTouchEvent进行处理 returnfalse: 表示不对事件进行拦截,事件得以成功分发到子View returnsuper.onInterceptTouchEvent(ev): 默认表示拦截该事件,并将事件传递给当前View的onTouchEvent方法 onTouchEvent returntrue: 表示onTouchEvent处理完事件后消费了此次事件 returnfasle: 表示不响应事件,那么该事件将会不断向上层View的onTouchEvent方法传递,直到某个View的onTouchEvent方法返回true returnsuper.dispatchTouchEvent(ev): 表示不响应事件,结果与returnfalse一样 Android事件分发机制的分发流程 这里以网上的图片来说明,如果对上面分发例子还不太懂的同学,看这张图片已经很生动的说明了整个过程 ViewGroup事件分发源码分析 我们这里以ViewGroup的dispatchTouchEvent()方法开始讲解,这里面主要有两件事情 询问是否拦截事件 遍历子View并分发事件 一、dispatchTouchEvent源码询问拦截事件 @Override publicbooleandispatchTouchEvent(MotionEventev){ ...... //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; } }else{ //Therearenotouchtargetsandthisactionisnotaninitialdown //sothisviewgroupcontinuestointercepttouches. intercepted=true; } ...... } ViewGroup在两种情况下都会判断是否要拦截当前事件 事件类型为ACTION_DOWN: 当前由我们触发的点击事件,也即是说ACTION_MOVE和ACTION_UP事件来时,则不触发拦截事件 mFirstTouchTarget! =null: 当ViewGroup不拦截事件并将事件交给子View的时候该不等式成立。 反过来,事件被ViewGroup拦截时,该不等式不成立 二、dispatchTouchEvent源码遍历子View并分发事件 @Override publicbooleandispatchTouchEvent(MotionEventev){ ...... finalView[]children=mChildren; //遍历所有子View for(inti=childrenCount-1;i>=0;i--){ finalintchildIndex=getAndVerifyPreorderedIndex( childrenCount,i,customOrder); finalViewchild=getAndVerifyPreorderedView( preorderedList,children,childIndex); //判断子View是否能接收点击事件 if(childWithAccessibilityFocus! =null){ if(childWithAccessibilityFocus! =child){ continue; } childWithAccessibilityFocus=null; i=childrenCount-1; } //判断子元素在播放动画时落在子元素的区域内 if(! canViewReceivePointerEvents(child) ||! isTransformedTouchPointInView(x,y,child,null)){ ev.setTargetAccessibilityFocus(false); continue; } //判断子元素点击事件是否落在子元素的区域内 newTouchTarget=getTouchTarget(child); if(newTouchTarget! =null){ //Childisalreadyreceivingtouchwithinitsbounds. //Giveitthenewpointerinadditiontotheonesitishandling. newTouchTarget.pointerIdBits|=idBitsToAssign; break; } resetCancelNextUpFlag(child); //事件传递到子View,下面追踪该方法 if(dispatchTransformedTouchEvent(ev,false,child,idBitsToAssign)){ //Childwantstoreceivetouchwithinitsbounds. mLastTouchDownTime=ev.getDownTime(); if(preorderedList! =null){ //childIndexpointsintopresortedlist,findoriginalindex for(intj=0;j if(children[childIndex]==mChildren[j]){ mLastTouchDownIndex=j; break; } } }else{ mLastTouchDownIndex=childIndex; } mLastTouchDownX=ev.getX(); mLastTouchDownY=ev.getY(); newTouchTarget=addTouchTarget(child,idBitsToAssign); alreadyDispatchedToNewTouchTarget=true; break; } //Theaccessibilityfocusdidn'thandletheevent,soclear //theflaganddoanormaldispatchtoallchildren. ev.setTargetAccessibilityFocus(false); } ...... } ViewGroup直接使用for遍历所有子View,对子View的各种状态进行判断,最后调用dispatchTransformedTouchEvent(ev,false,child,idBitsToAssign)将事件传递给子View,下面是dispatchTransformedTouchEvent()方法的部分源码 if(child==null){ handled=super.dispatchTouchEvent(event); }else{ handled=child.dispatchTouchEvent(event); } 其最后就是分发给子View的dispatchTouchEvent()方法,那么事件就分发到子View中去了 View事件分发源码分析 View对点击事件的处理过程主要有 View的dispatchTouchEvent(): 判断分发事件 View的onTouchEvent(): 处理事件的具体做法 一、dispatchTouchEvent源码判断分发事件部分 publicbooleandispatchTouchEvent(MotionEventevent){ booleanresult=false; ...... if(onFilterTouchEventForSecurity(event)){ if((mViewFlags&ENABLED_MASK)==ENABLED&&handleScrollBarDragging(event)){ result=true; } //noinspectionSimplifiableIfStatement ListenerInfoli=mListenerInfo; //这里开始判断 if(li! =null&&li.mOnTouchListener! =null &&(mViewFlags&ENABLED_MASK)==ENABLED
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Android 进阶 事件 分发 机制 dispatchTouchEventonInterceptTouchEventonTouchEvent
链接地址:https://www.bdocx.com/doc/28869607.html