重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
[图片上传失败...(image-85aaf7-1630895208631)]
发展壮大离不开广大客户长期以来的信赖与支持,我们将始终秉承“诚信为本、服务至上”的服务理念,坚持“二合一”的优良服务模式,真诚服务每家企业,认真做好每个细节,不断完善自我,成就企业,实现共赢。行业涉及木屋等,在成都网站建设、网络营销推广、WAP手机网站、VI设计、软件开发等项目上具有丰富的设计经验。
[图片上传失败...(image-8c09b-1630895208631)]
[图片上传失败...(image-25abb8-1630895208631)]
日常处理的部分为RootView下面的ViewGroup和View部分,那么上面的PhoneWindow、DecorView和RootView是做什么用的呢?RootView本身可以作为上下沟通的桥梁使用。
(设计模式-组合模式)
PhoneWindow是Window的实现类,Window是抽象类,DecorView是它的一个内部类。所以,PhoneWindow的大部分消息,都是PhoneWindow通过DecorView传递给下面的View的,同时下面的View传递消息也是通过DecorView回传给PhoneWindow。
事件的传递过程中,主要有三种情况:事件分发(dispatchTouchEvent)、事件拦截(onInterceptTouchEvent)、事件消费(onTouchEvent)。这三种情况均有一个boolean型的返回值来控制事件的传递流程。
为什么只有ViewGroup有事件拦截:因为Activity作为事件分发的开始,拦截了就只能自己处理了;而View作为事件分发的最末端,拦不拦截都需要它处理。中间阶段,拦截可做一些处理。
事件传递的顺序:
Activity - PhoneWindow - DecorView - ViewGroup - View - Activity
如果我们点击View1,系统如何传递给View1呢,而不是下面的ViewGroupA或者RootView。很明显,我们需要一种机制来执行消息的分发。而消息分发的最小单位是View,ViewGroup是View的子类,Activity是根布局.
事件消费与否与具体消费无关,仅由返回值决定,true表示消费,false表示不消费。
事件分发,总觉得不好理解,感觉非常麻烦,因为它涉及到的东西实在太多了,到底怎么分发与以下因素都有关:在哪个视图层级(Activity、ViewGroup、View),什么事件类型(DOWN、MOVE、UP、CANCEL),在哪个回调方法(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent),回调方法返回不同的返回值(true、false)。这些因素都会影响事件的分发,如果单纯死记硬背,就算当时背过了,过一段时间也就忘了,所以,真正理解事件分发,才是搞懂事件分发的关键。要理解事件分发,那我们就需要弄清楚,为什么需要事件分发,它具体又是做了什么呢?
我们现在知道,事件是Activity-ViewGroup-View这样层层传递的,每个层级都应该有处理事件的能力,显然,我们需要两个方法,一个用来传递事件,一个用来处理时事件。我们分别定义三个类:MActivity,MViewGroup,MView 来分别模拟Activity,ViewGroup和View,一步一步实现事件分发。
这个需求很简单,我们只是需要最里层View处理事件,假如,不光最里层View可以处理事件,包裹它的ViewGroup也能处理事件,这应该怎么办呢?比如,ViewGroup是可以点击的。
【透镜系列】看穿 触摸事件分发
工作当中遇到一个需求:有两个重叠并且全屏的Framelayout,交互逻辑是点击上层的button使得上层消失,下层可见;再点击下层使得下层消失上层出现。但是发现当点击上层非button区域时,下层也会响应点击事件,但是点击button区域则不会。这意味着点击事件穿过上层到达下层。对于安卓事件机制一知半解的我无从下手,上网搜了一下发现在上层FrameLayout下增加:
这样的确可以保证上层点击事件不会到达下层,可是这是为什么呢?最初步的猜想是当上层FrameLayout的clickable属性为true时,点击事件已经被上层拦截了。这个和当你点击button时响应onclick()时的原理是不是一样?这就需要从源码分析了。
分析源码前先大致了解一下安卓事件分发机制。
综合上述对安卓事件分发的源码分析知道,当在上层FrameLayout中将clickable设置为true时,其实就是
当点击事件到达上层framelayout时,在onTouchEvent中对事件进行拦截,使得点击事件不会继续向下传递。当然,除了这个方法以外,也可以重写FrameLayout的onInterceptTouchEvent,在将这个函数的返回值为true,也可以实现拦截事件的作用。
Android中对视图的Touch事件进行分发处理。
单手指操作:ACTION_DOWN - ACTION_MOVE - ACTION_UP
多手指操作:ACTION_DOWN - ACTION_POINTER_DOWN - ACTION_MOVE - ACTION_POINTER_UP - ACTION_UP.
(1) dispatchTouchEvent() :事件分发
(2) onInterceptTouchEvent() :事件拦截
(3) onTouchEvent() :事件处理
ViewGroup 的相关事件有三个:onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent。
View 的相关事件只有两个:dispatchTouchEvent、onTouchEvent。
先分析ViewGroup的处理流程:首先得有个结构模型概念:ViewGroup和View组成了一棵树形结构,最顶层为Activity的ViewGroup,下面有若干的ViewGroup节点,每个节点之下又有若干的ViewGroup节点或者View节点,依次类推。如图:
点击事件达到顶级 View(一般是一个 ViewGroup),会调用 ViewGroup 的 dispatchTouchEvent 方法,如果顶级 ViewGroup 拦截事件即 onInterceptTouchEvent 返回 true,则事件由 ViewGroup 处理,这时如果 ViewGroup 的 mOnTouchListener 被设置,则 onTouch 会被调用,否则 onTouchEvent 会被调用。也就是说如果都提供的话,onTouch 会屏蔽掉 onTouchEvent。在 onTouchEvent 中,如果设置了 mOnClickListenser,则 onClick 会被调用。如果顶级 ViewGroup 不拦截事件,则事件会传递给它所在的点击事件链上的子 View,这时子 View 的 dispatchTouchEvent 会被调用。如此循环。