Android事件分发机制,也被称为“事件处理机制”,“Touch处理机制”等等,指的是对用户触摸屏幕后引发的一系列Touch事件的处理机制,例如用户点击一次屏幕,该事件到底是页面上的哪个View来处理,为什么?
MotionEvent事件主要有:down,move,up
主要分析的类:ViewGroup,View和特殊的View(ListView,ScrollView等)
主要分析的方法:dispatchTouchEvent,onInterceptTouchEvent,onTouchEvent
知识背景
Activity管理着一个Window,具体的实现类PhoneWindow,PhoneWindow里面有个DecorView的对象,DecorView分为两部分,title和content。我们在Activity里面调用setContentView,就是给content部分加载布局
事件传递流程源码分析(API 27)
- 先看Activity.java,在dispatchTouchEvent中,会执行getWindow().superDispatchTouchEvent(ev),调用mWindow的superDispatchTouchEvent(ev),即将事件传递给PhoneWindow
// Activity.java
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
// getWindow()放回mWindow对象,调用mWindow的superDispatchTouchEvent
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
public Window getWindow() {
return mWindow;
}
private Window mWindow; // PhoneWindow是Window的唯一实现类
final void attach(...) {
...
// 给mWindow赋值
mWindow = new PhoneWindow(this, window, activityConfigCallback); ...
}
- 在PhoneWindow中又直接将事件传递到DecorView的superDispatchTouchEvent
// PhoneWindow.java
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
// 调用mDecor的方法
return mDecor.superDispatchTouchEvent(event);
}
// This is the top-level view of the window, containing the window decor.
private DecorView mDecor; // 申明
public PhoneWindow(...) {
...
mDecor = (DecorView) preservedWindow.getDecorView(); // 初始化
...
}
- DecorView调用父类ViewGroup的superDispatchTouchEvent
// DecorView.java
public boolean superDispatchTouchEvent(MotionEvent event) {
// DecorView继承FrameLayout,而FrameLayout没有重写dispathToucheEvent,所以这里将会调用FrameLayout的父类ViewGroup的dispatchTouchEvent
return super.dispatchTouchEvent(event);
}
- ViewGroup部分源码,主要方法dispatchTouchEvent,dispatchTransformedTouchEvent
// ViewGroup.java
public boolean dispatchTouchEvent(MotionEvent ev) {
...
// Handle an initial down.
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Throw away all previous state when starting a new touch gesture.
// The framework may have dropped the up or cancel event for the previous gesture
// due to an app switch, ANR, or some other state change.
cancelAndClearTouchTargets(ev);
// 每次ACTION_DOWN,都会通过resetTouchState,将mFirstTouchTarget和mGroupFlags重置
resetTouchState();
}
// Check for interception ====================================
final boolean intercepted; // 申明局部变量intercepted标记事件是否要拦截
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;