Android中事件分发涉及到三个View,Activity ViewGroup View,而事件的传递顺序是从Activity-->ViewGroup-->View;涉及到三个方法
dispatchTouchEvent() onTouchEvent() onInterceptTouEvent。之后我会从源码的角度来分析事件分发的过程
一、Activity的事件分发
我们先从事件的开头来介绍。当有一个action发生时,最先执行的就是Activity中的dispatchTouchEvent,源码如下图
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
dispatchTouchEvent方法是有一个布尔的返回值,当返回true,表示事件在当前Activity中被处理掉了,不在向下进行事件的分发操作了。而源码中getWindow所得到的类是一个抽象类,所以我们需要找到具体的实现类,而Activity的布局图如下,PhoneWindow其实就是Window抽象类的实现类。
我们去看PhoneWindow中的superDispatchTouchEvent,源码如下
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
而mDecor就是上图中DecorView,我们查看DecorView中的superDispathchTouchEvent,源码如下
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
DecorView的父类是FrameLayout,而FrameLayout的父类是ViewGroup,所以,事件到了这里就传递到了ViewGroup中的dispatchTouchEvent
二、ViewGroup中的事件分发
接着上面说的,我们来查看ViewGroup中的dispatchTouchEvent,我从中挑出重点部分来说
事件的拦截 onInterceptTouchEvent,从源码中我们可以看到,onInterceptTouchEvent我们是可以覆写的,intercepted就是我们覆写后的值
final boolean intercepted;
if (actionMasked == MotionEvent.ACTION_DOWN
|| mFirstTouchTarget != null) {
final boolean disallowIntercept = (mGroupFlags & FLAG_DISALLOW_INTERCEPT) != 0;
if (!disallowIntercept) {
intercepted = onInterceptTouchEvent(ev);
ev.setAction(action); // restore action in case it was changed
} else {
intercepted = false;
}
} else {
// There are no touch targets and this action is not an initial down
// so this view group continues to intercept touches.
intercepted = true;
}
我们继续向下看源码,看到一个for循环,进行子View的遍历
final View[] children = mChildren;
for (int i = childrenCount - 1; i >= 0; i--) {
final int childIndex = getAndVerifyPreorderedIndex(
childrenCount, i, customOrder);
final View child = getAndVerifyPreorderedView(
preorderedList, children, childIndex);
我们在for循环中发现了dispatchTransformedTouchEvent方法,从方法名的字面翻译就是分发传递事件,我们点进去查看源码,发现源码中有两个比较重要的代码,无论是child,还是super其实都是View,所以事件传递到了View中
handled = child.dispatchTouchEvent(event);
handled = super.dispatchTouchEvent(event);
三、View中的事件分发
接着上面,我们查看View中的dispatchTouchEvent源码发现,这个方法的返回值是result变量,而使result值改变的位置有三个,如下
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
if (!result && onTouchEvent(event)) {
result = true;
}
第一个if:如果当前View可用并且是当做滚动条来处理,则返回true
第二个if:(1)OnTouchListener监听对象不为空
(2)当前view可用
(3)覆写了onTouch方法
第三个if:执行了onTouchEvent方法
我们查看onTouchEvent方法,发现只要clickable为true就会返回true。表示如果当前view可以点击,那么当前view就会处理action
到这里,事件分发机制的源码就分析完了