Android事件分发机制三:事件分发工作流程

在前两篇文章中,Android事件分发机制一:事件是如何到达activity的? 分析了事件分发的真正起点:viewRootImpl,Activity只是其中的一个环节;Android事件分发机制二:viewGroup与view对事件的处理 源码解析了viewGroup和view是如何分发事件的。

事件分发的核心内容,则为viewGroup和view对事件的分发,也就是第二篇文章。第二篇文章对源码的分析较为深入,缺乏一个更高的角度来审视事件分发流程。本文在前面的分析基础上,对整个事件分发的工作流程进行一个总结,更好地把握事件是如何在不同的对象和方法之间进行传递。

回顾

先来回顾一下整体的流程,以便更好地定位我们的知识。

Android事件分发机制三:事件分发工作流程

触摸信息从手机触摸屏幕时产生,通过IMS和WMS发送到viewRootImpl

viewRootImpl通过调用view的dispatchPointerEvent方法把触摸信息传递给view

view通过调用自身的dispatchTouchEvent方法开始了事件分发

图中的view指的是一个控件树,他可以是一个viewGroup也可以是一个简单的view。因为viewGroup是继承自view,所以一个控件树,也可以看做是一个view。

我们今天探讨的工作流程,就是从图中的view调用自身的dispatchTouchEvent开始。

主要对象与方法 事件分发的对象

这一部分内容在第二篇有详细解析,这里做个简单的回顾。

当我们手机触碰屏幕时会产生一系列的MotionEvent对象,根据触摸的情况不同,这些对象的类型也会不同。具体如下:

ACTION_DOWN: 表示手指按下屏幕

ACTION_MOVE: 手指在屏幕上滑动时,会产生一系列的MOVE事件

ACTION_UP: 手指抬起,离开屏幕、

ACTION_CANCEL:当出现异常情况事件序列被中断,会产生该类型事件

ACTION_POINTER_DOWN: 当已经有一个手指按下的情况下,另一个手指按下会产生该事件

ACTION_POINTER_UP: 多个手指同时按下的情况下,抬起其中一个手指会产生该事件

事件分发的方法

事件分发属于控件系统的一部分,主要的分发对象是viewGroup与view。而其中核心的方法有三个: dispatchTouchEvent 、onInterceptTouchEvent 、 onTouchEvent 。那么在讲分发流程之前,先来介绍一下这三个方法。这三个方法属于view体系的类,其中Window.CallBack接口中包含了 dispatchTouchEvent 和 onTouchEvent 方法,Activity和Dialog都实现了Window.CallBack接口,因此都实现了该方法。因这三个方法经常在自定义view中被重写,以下的分析,如果没有特殊说明都是在默认方法实现的情况下。

dispatchTouchEvent

该方法是事件分发的核心方法,事件分发的逻辑都是在这个方法中实现。该方法存在于类View中,子类ViewGroup、以及其他的实现类如DecorView都重写了该方法。

无论是在viewGroup还是view,该方法的主要作用都是处理事件。如果成功处理则返回true,处理失败则返回false,表示事件没有被处理。具体到类,在viewGroup相关类中,该方法的主要作用是把事件分发到该viewGroup所拥有的子view,如果子view没有处理则自己处理;在view的相关类中,该方法的主要作用是消费触摸事件。

onInterceptTouchEvent

该方法只存在于viewGroup中,当一个事件需要被分发到子view时,viewGroup会调用此方法检查是否要进行拦截。如果拦截则自己处理,而如果不拦截才会调用子view的 dispatchTouchEvent 方法分发事件。

方法返回true表示拦截事件,返回false表示不拦截。

这个方法默认只对鼠标的相关操作的一种特殊情况进行了拦截,其他的情况需要具体的实现类去重写拦截。

onTouchEvent

该方法是消费事件的主要方法,存在于view中,viewGroup默认并没有重写该方法。方法返回true表示消费事件,返回false表示不消费事件。

viewGroup分发事件时,如果没有一个子view消费事件,那么会调用自身的onTouchEvent方法来处理事件。View的dispatchTouchEvent方法中,并不是直接调用onTouchEvent方法来消费事件,而是先调用onTouchListener判断是否消费;如果onTouchListener没有消费事件,才会调用onTouchEvent来处理事件。

我们为view设置的onClickListener与onLongClickListener都是在View的dispatchTouchEvent方法中,根据具体的触摸情况被调用。

重要规则

事件分发有一个很重要的原则:一个触控点的事件序列只能给一个view消费,除非发生异常情况如被viewGroup拦截 。具体到代码实现就是:消费了一个触控点事件序列的down事件的view,将持续消费该触控点事件序列接下来的所有的事件 。举个栗子:

当我手指按下屏幕时产生了一个down事件,只有一个view消费了这个down事件,那么接下来我的手指滑动屏幕产生的move事件会且仅会给这个view消费。而当我手机抬起,再按下时,这时候又会产生新的down事件,那么这个时候就会再一次去寻找消费down事件的view。所以,事件分发,是以事件序列为单位的

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpxwzp.html