一、前介
1、事件分发的对象是谁?
答:点击事件(Touch事件)
- 定义
当用户触摸屏幕时(View 或 ViewGroup派生的控件),将产生点击事件(Touch事件)
Touch事件的相关细节(发生触摸的位置、时间等)被封装成
MotionEvent
对象
- 事件类型(4种)
- 特别说明:事件列
从手指接触屏幕 至 手指离开屏幕,这个过程产生的一系列事件
注:一般情况下,事件列都是以DOWN
事件开始、UP
事件结束,中间有无数的MOVE
事件,action_cancel的具体动作是在非人为原因,比如父view打断了正在进行的子view,会执行action_cancel
,如下图:
即当一个点击事件(MotionEvent
)产生后,系统需把这个事件传递给一个具体的 View
去处理。
2、事件分发的本质
答:将点击事件(
MotionEvent
)传递到某个具体的View
& 处理的整个过程
即 事件传递的过程 = 分发过程。
3、事件在哪些对象之间进行传递?
答:Activity、ViewGroup、View
Android的UI界面由Activity、ViewGroup、View
及其派生类组成
UI界面
4、事件分发的顺序
即 事件传递的顺序:
Activity -> ViewGroup -> View
即:1个点击事件发生后,事件先传到Activity、再传到ViewGroup、最终再传到 View
5、事件分发过程由哪些方法协作完成?
答:
dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()
其中Activity、ViewGroup、View分别对应的方法如下:
- Activity:
dispatchTouchEvent() 、onTouchEvent()
;- ViewGroup:
dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()
;- View:
dispatchTouchEvent() 、onTouchEvent()
;
下文会对这3个方法进行详细介绍
二、源码分析
- 请谨记:Android事件分发流程 =
Activity -> ViewGroup -> View
- 即:1个点击事件发生后,事件先传到Activity、再传到ViewGroup、最终再传到 View
要想充分理解Android分发机制,本质上是要理解:
- Activity对点击事件的分发机制
- ViewGroup对点击事件的分发机制
- View对点击事件的分发机制
下面,我将通过源码,全面解析 事件分发机制
1、 Activity的事件分发机制
当一个点击事件发生时,事件最先传到Activity的dispatchTouchEvent()进行事件分发
1.1 源码分析
/**
* 源码分析:Activity.dispatchTouchEvent()
*/
public boolean dispatchTouchEvent(MotionEvent ev) {
// 一般事件列开始都是DOWN事件 = 按下事件,故此处基本是true
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
// ->>分析1
}
// ->>分析2
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
// 若getWindow().superDispatchTouchEvent(ev)的返回true
// 则Activity.dispatchTouchEvent()就返回true,则方法结束。即 :该点击事件停止往下传递 & 事件传递过程结束
// 否则:继续往下调用Activity.onTouchEvent
}
// ->>分析4
return onTouchEvent(ev);
}
/**
* 分析1:onUserInteraction()
* 作用:实现屏保功能
* 注:
* a. 该方法为空方法
* b. 当此activity在栈顶时,触屏点击按home,back,menu键等都会触发此方法
*/
public void onUserInteraction() {
}
// 回到最初的调用原处
/**
* 分析2:getWindow().superDispatchTouchEvent(ev)
* 说明:
* a. getWindow() = 获取Window类的对象
* b. Window类是抽象类,其唯一实现类 = PhoneWindow类;即此处的Window类对象 = PhoneWindow类对象
* c. Window类的superDispatchTouchEvent() = 1个抽象方法,由子类PhoneWindow类实现
*/
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
// mDecor = 顶层View(DecorView)的实例对象
// ->> 分析3
}
/**
* 分析3:mDecor.superDispatchTouchEvent(event)
* 定义:属于顶层View(DecorView)
* 说明:
* a. DecorView类是PhoneWindow类的一个内部类
* b. DecorView继承自FrameLayout,是所有界面的父类
* c. FrameLayout是ViewGroup的子类,故DecorView的间接父类 = ViewGroup
*/
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
// 调用父类的方法 = ViewGroup的dispatchTouchEvent()
// 即 将事件传递到ViewGroup去处理,详细请看ViewGroup的事件分发机制
}
// 回到最初的调用原处
/**
* 分析4:Activity.onTouchEvent()
* 定义:属于顶层View(DecorView)
* 说明:
* a. DecorView类是PhoneWindow类的一个内部类
* b. DecorView继承自FrameLayout,是所有界面的父类
* c. FrameLayout是ViewGroup的子类,故DecorView的间接父类 = ViewGroup
*/
public boolean onTouchEvent(MotionEvent event) {
// 当一个点击事件未被Activity下任何一个View接收 / 处理时
// 应用场景:处理发生在Window边界外的触摸事件
// ->> 分析5
if (mWindow.shouldCloseOnTouch(this, event)) {
finish()