Android事件分发机制

什么是事件分发

  • 用户通过屏幕与手机交互的时候,每一次点击、长按、移动等都是一个事件。
  • 事件分发机制:某一个事件从屏幕传递到各个View,由View来使用这一事件(消费事件)或者忽略这一事件(不消费事件),这整个过程的控制。

事件分发的对象是谁

  • 系统把事件封装为MotionEvent对象,事件分发的过程就是MotionEvent分发的过程。

事件类型

  • 按下(ACTION_DOWN)
  • 移动(ACTION_MOVE)
  • 抬起(ACTION_UP)
  • 取消(ACTION_CANCEL)

事件序列

  • 从手指按下屏幕开始,到手指离开屏幕所产生的一系列事件。

传递层级

  • Activity -> Window -> DecorView -> ViweGroup -> View

了解以上基础知识,我们先来看Activity的事件分发流程

先来一张分发流程图,对分发过程有一个印象,帮助理解后续源码分析

Android事件分发机制

事件传递首先会从Activity的dispatchTouchEvent方法进入,我们直接看源码:

Android事件分发机制

如果当前事件为Down事件,会调用onUserInteraction()方法。

Android事件分发机制

我们可以看到,这个方法是个空方法。接下来看getWindow().superDispatchTouchEvent(ev)

Android事件分发机制

getWindow获取的是Window,但是Window是一个抽象类,我们知道Window的实现类是PhoneWindow,从源码可以看出来,在Window的说明中,有这么一段话:

Android事件分发机制

这段话说明了Window的唯一实现类是PhoneWindow。

然后我们继续看PhoneWindow中的方法superDispatchTouchEvent方法:

Android事件分发机制

发现调用的是DecorView的superDispatchTouchEvent方法,那么DecorView是什么呢?

DecorView是Activity最顶层的View,也就是当前界面的底层容器(即setContentView所设置的View的父容器),通过Activity.getWindow().getDecorView()可以获得。

继续看DecorView里面的superDispatchTouchEvent方法,实现在Viewgroup,因为DecorView是继承于FrameLayout,这样事件就从Activity中传递到ViewGroup中。

Android事件分发机制

ok,以上是Activity的事件分发过程,下面我们继续分析ViewGroup的事件分发机制

同样我们先放一张ViewGroup的分发流程图

Android事件分发机制

ViewGroup的实现方法比较长,我们挑重点讲

Android事件分发机制

首先会执行onFilterTouchEventForSecurity(ev)方法,作用是判断当前的触摸事件是否符合安全策略,用户只能点击看得到的view,看不到的没有办法点击,如果某个view不处于视图的顶部的话,也就是说当前view没有和用户直接交互,则该view不会响应事件,该方法返回false。

Android事件分发机制

如果事件是ACTION_DOWN,会进行初始化操作

Android事件分发机制

然后查看事件的拦截情况

Android事件分发机制

如果intercepted为true,事件不会继续传递,由当前ViewGroup处理,如何为false,继续传递到它下面的子View处理。

当disallowIntercept返回false,会执行onInterceptTouchEvent(ev)

Android事件分发机制

当此方法为true,表示事件会被拦截,否则,继续向子View传递。继续向下看

Android事件分发机制

首先遍历ViewGroup的所以子元素,然后判断子元素是否能接收到点击事件。

Android事件分发机制dispatchTransformedTouchEvent方法调用的就是子元素的dispatchTouchEvent方法,在它的内部有如下一段内容

Android事件分发机制

如何child为不为null,会直接调用子元素的dispatchTouchEvent方法,这样事件就交由子元素处理了,从而完成了一轮事件分发。

如果子元素的dispatchTouchEvent返回true,这时我们暂时不用考虑事件在子元素内部是怎么分发的,那么mFirstTouchTarget就会被赋值同时跳出for循环,如下所示

Android事件分发机制

这几行代码完成了mFirstTouchTarget的赋值并终止对子元素的遍历。如果子元素的dispatchTouchEvent返回false,ViewGroup就会把事件分发给下一个元素。

以上是ViewGroup的分发过程,接下来我们继续看View的分发过程

同样,先上图

Android事件分发机制

Android事件分发机制同样,先判断是否符合安全策略,然后判断有没有设置OnTouchListener,如果OnTouchListener中的ontouch方法返回true,那么onTouchEvent就不会被调用,可见OnTouchListener的优先级高于onTouchEvent,这样的做的好处是方便在外界处理点击事件。

接着再分析onTouchEvent的实现。

Android事件分发机制

当View处于不可用状态下,依然会消耗点击事件。

接着,如果View设置有代理,那么还会执行TouchDelegat的onTouchEvent方法,这个onTouchEvent的工作机制看起来和OnTouchListener类似,这里不深入研究了。

Android事件分发机制

好了,以上为View事件分发的整个过程。