一、前言
用户在使用app时,会经常频繁的触摸屏幕,点击页面交互,打开需要的功能。用户触摸点击的动作,就涉及到app中相关UI的触摸和点击事件。事件在UI中传递和处理的过程,就是事件分发流程。
二、事件分发流程概述
事件分发过程中,涉及到三种UI对象类型:Activity、ViewGroup、View 及其派生类。三者之间的关系如下图:
发生一次点击事件时,事件会按照Activity->ViewGroup->View的顺序,进行事件传递。
- Activity:控制UI页面的生命周期,是事件分发的入口。
- ViewGroup:View的特殊子类,是一组View的集合,是Android中所有布局的父类。
- View:所有UI组件的基类,常见的Button、TextView等控件都继承自View。
Android事件分发机制,其实就是Activity、ViewGroup、View三者对触摸点击事件的事件传递过程。
三、事件分发流程详细分析
在整个事件分发,并响应事件的过程中,有三个重要的方法:
- dispatchTouchEvent:分发(传递)点击事件,当点击事件能够传递给当前View时,该方法就会被调用。
- onInterceptTouchEvent:判断是否拦截某个事件,该方法仅在ViewGroup中存在。一般情况下会在ViewGroup的dispatchTouchEvent方法中调用该方法。
- onTouchEvent:处理点击事件,在dispatchTouchEvent内部调用。
下面依次对Activity、ViewGroup、View三种UI对象类型,结合上述三个事件方法,做一下具体分析。
3.1 Activity的事件分发流程
Activity 中包含两个事件分发与处理的方法,分别是:
- boolean dispatchTouchEvent(MotionEvent ev):事件分发
- boolean onTouchEvent(MotionEvent event):事件消费
当一个事件发生时,首先会将点击事件传递到Activity中,执行dispatchTouchEvent进行事件分发。经过window、decorView依次传递后,页面上的 ViewGroup会接收到该事件。ViewGroup如果消费了该事件,则分发结束,未消费则继续调用Activity的onTouchEvent 方法处理事件,简略流程图如下:
3.2 ViewGroup的事件分发流程
ViewGroup 中包含三个事件分发与处理的方法,分别是:
- dispatchTouchEvent(MotionEvent ev):事件分发
- onIntercepTouchEvent(MotionEvent ev):事件拦截
- onTouchEvent(MotionEvent ev):事件消费
ViewGroup的事件分发机制从
dispatchTouchEvent开始,接着调用onInterceptTouchEvent方法判断是否需要拦截事件。
如果需要拦截,则表示当前 ViewGroup 希望处理该事件,或者不希望子 View 处理该事件,此时将直接调用 onTouchEvent方法处理事件。onTouchEvent方法如果消费了该事件,则分发结束,未消费则调用Activity的onTouchEvent方法处理事件。
如果不需要拦截,则会遍历寻找被点击的子View,将该事件传递给子 View 的 dispatchTouchEvent 方法。如果未找到子View,事件将会继续传递给ViewGroup的onTouchEvent方法,与事件被拦截的效果一致。
主要的事件分发链路图如下所示:
3.3 View的事件分发流程
View 中包含如下两个事件分发与处理的方法,分别是:
- dispatchTouchEvent(MotionEvent event)
- onTouchEvent(MotionEvent event)
View通过
dispatchTouchEvent方法接收到从ViewGroup传递过来的事件后,直接调用onTouchEvent方法处理事件。如果消费了该事件,则分发结束,未消费则调用ViewGroup的onTouchEvent方法处理事件。所以 View 中的事件处理流程很简单,如下图:
此处说明一个细节,当View把事件消费后,如果View的onTouch方法返回true,View的dispatchTouchEvent方法会直接返回true,不会再调用View的onClick方法。只有当onTouch方法返回false时,才会有onClick事件处理。
四、总结
Android事件分发流程:Activity -> ViewGroup -> View。即:1个点击事件发生后,事件先传到Activity、再传到ViewGroup、最终再传到View。从上往下依次调用dispatchTouchEvent(),进行事件分发。
Android事件消费流程:View -> ViewGroup -> Activity。从下往上依次调用onTouchEvent(),进行事件响应处理。
事件如果在传递过程中被消费,整个分发流程则直接结束。