Android Touch分发事件机制详解
**********如果你理解起来比较困难,那你可以看看我的东西,一行一行读下去,至少理解肯定没问题*****
这里主要是针对面试的速成知识点:
原文:https://www.jianshu.com/p/38015afcdb58这里写的特别棒
http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html
事件分发主要是指对Touch事件的处理,何为Touch事件?
就是我们常说的点击,触摸事件
Touch事件的相关细节被封装成了一个事件对象:
(发生触摸的位置、时间等)MotionEvent对象
概念**********************************************************************************************
###一个定义:那么Touch事件的分发过程,就是指MotionEvent对象的传递,最终由谁来处理的过程;
或者说事件(MotionEvent)传递到某个具体的View & 处理的整个过程
事件传递的过程 = 分发过程
###四种类型:Touch事件类型:
MotionEvent.ACTION_DOWN按下View(所有事件的开始)
MotionEvent.ACTION_UP抬起View(与DOWN对应)
MotionEvent.ACTION_MOVE滑动View
MotionEvent.ACTION_CANCEL结束事件(非人为原因)
一般手机触摸屏幕,再离开屏幕的过程,会出发一系列的Touch事件
一般情况下,事件列都是以DOWN事件开始、UP事件结束,中间有无数的MOVE事件
当一个事件(MotionEvent )产生后,系统需把这个事件传递给一个具体的 View去处理
原理和过程分析:****************************************************************************
###主要三个对象:Activity,ViewGroup,View
事件传递是在Activity,ViewGroup,View之间传递
事件传递的顺序:Activity -> ViewGroup -> View
即:1个点击事件发生后,事件先传到Activity、再传到ViewGroup、最终再传到 View
###主要三个方法:
dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()
三个对象,每个对象里都有dispatchTouchEvent()和onTouchEvent()方法
ViewGroup里多了一个onInterceptTouchEvent()
**********把以下的分析明白就OK了
这里直接教你面试的时候怎么说:
(1)Activity对点击事件的分发机制
首先会先回掉Activity的dispatchTouchEvent方法,最终会交给ViewGroup的
dispatchTouchEvent()处理。
过程:————————————————————————————————————---------------------
getWindow获取window类的对象,指向唯一的实现类Phonewindow对象,然后再调用他
的superDispatchTouchEvent(ev)方法:
里面调用到:
mDecor.superDispatchTouchEvent(event);
mDecor是(DecorView)的实例对象
a. DecorView类是PhoneWindow类的一个内部类
b. DecorView继承自FrameLayout,是所有界面的父类
c. FrameLayout是ViewGroup的子类,故DecorView的间接父类 = ViewGroup
// 调用父类的方法 = ViewGroup的dispatchTouchEvent()// 即 将事件传递到ViewGroup去处理
—————————————————————————————————————————————
ViewGroup的dispatchTouchEvent如果返回true,则不会再执行Activty的OnTouchEvent()方法;
ViewGroup的dispatchTouchEvent如果返回false,则继续执行Activty的OnTouchEvent()方法;
OnTouchEvent这个方法是在当Activty上面所有的View都没有接收处理这个事件的时候
而且要求Activity的dispatchTouchEvent返回false super.OnTouchEvent,才会触发
第一种情况:
比如说你的Activity上什么都没有,但是你触摸了屏幕就一定会触发dispatchTouchEvent,如果没有View消费掉事件,那么会继续触发OnTouchEvent()事件
第二种情况:
如果Activty上有一个按钮,给按钮添加一个点击事件,那么这个按钮被点击时会触发Activity的dispatchTouchEvent方法,但是这个事件被Activity中的Button消费掉 了,那么Activity的OnTouchEvent就不会再继续执行了
注意:
如果Activty的dispatchTouchEvent直接返回false或者True,那么OnTouchEvent()和按钮都不会接收到这个事件了
(2)ViewGroup对点击事件的分发机制
再Activity分发事件的里面可以发现ViewGroup的事件分发也是从dispatchTouchEvent开始的,
在ViewGroup的dispatchTouchEvent,ViewGroup每次事件分发时,都需调用onInterceptTouchEvent()询问是否拦截事件,
ViewGroup.onInterceptTouchEvent()
* 作用:是否拦截事件
* 说明:
* a. 返回true = 拦截,即事件停止往下传递(需手动设置,即复写onInterceptTouchEvent(),从而让其返回true)
* b. 返回false = 不拦截(默认)
*/publicbooleanonInterceptTouchEvent(MotionEvent ev){returnfalse; }
如果没有拦截,通过for循环,遍历了当前ViewGroup下的所有子View
/ 判断当前遍历的View是不是正在点击的View,
从而找到当前被点击的View// 若是,则进入条件判断内部
// 条件判断的内部调用了该View的dispatchTouchEvent()// 即 实现了点击事件从ViewGroup到子View的传递
// 调用子View的dispatchTouchEvent后是有返回值的// 若该控件可点击,那么点击时,dispatchTouchEvent的返回值必定是true,因此会导致条件判断成立// 于是给ViewGroup的dispatchTouchEvent()直接返回了true,即直接跳出// 即把ViewGroup的点击事件拦截掉
如果onInterceptTouchEvent是拦截的状态
那么返回true = 拦截,即事件停止往下传递,由ViewGroup自己的函数OnTouchEvent等等来处理这个事件
(3)View对点击事件的分发机制
总结:
dispatchTouchEvent 和OnTouchEvent的结果一致,返回true代表事件被消费了
有一层的OnTouchEvent返回了true
被消费一定是在OnTouchEvent中消费,就是在哪一层消费的问题
默认是dispatchTouchEvent的调用会一层一层的向下传递,
OnTouchEvent会一层一层向上传递
就是这个意思:
Activity的dispatchTouchEvent 会调用到ViewGroup的dispatchTouchEvent,
ViewGroup的dispatchTouchEvent会调用到View的dispatchTouchEvent对象
如果有一层返回了true都代表事件被消费了
如果都返回false,那么就回掉Activity的OnTouchEvent方法消费
如果ViewGroup层的拦截器返回true代表拦截,那么就是ViewGroup这一层的OnTouchEvent消费事件
如过默认条件下没有拦截,由view处理,就回掉view的OnTouchEvent消费
如果没有传递到view层,那么onclick就不会被触发了