前一篇博客中,我们分析了ViewGroup传递触摸事件的流程,详见:
Android O: 触摸事件传递流程源码分析(上)
本篇博客,我们主要来看一下View传递触摸事件的流程。
ViewGroup在分发事件时,会调用dispatchTransformedTouchEvent方法,
将MotionEvent分发给合适的Child View或ViewGroup。
对于Child View而言,dispatchTransformedTouchEvent函数,
最终还是会调用View的dispatchTouchEvent方法。
现在我们就来看看View的dispatchTouchEvent方法:
public boolean dispatchTouchEvent(MotionEvent event) {
// If the event should be handled by accessibility focus first.
if (event.isTargetAccessibilityFocus()) {
// We don't have focus or no virtual descendant has it, do not handle the event.
if (!isAccessibilityFocusedViewOrHost()) {
return false;
}
// We have focus and got the event, then use normal event dispatch.
event.setTargetAccessibilityFocus(false);
}
............
从上面的代码可以看出,与ViewGroup处理MotionEvent的过程一致,
View也会先针对Accessibility Focus事件进行处理。
如果事件要求Accessibility Focus,但当前View不具备这种能力,
那么分发结束,直接返回false;
如果当前View具有Accessibility Focus能力,那么收到这种类型的事件后,
直接将MotionEvent对应的Flag置为false。
我们继续跟进代码:
//用于保存最终的结果,记录事件是否被当前View消费掉
boolean result = false;
//这部分应该和测试相关
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onTouchEvent(event, 0);
}
//收到新开始的事件,清除旧有的记录信息
final int actionMasked = event.getActionMasked();
if (actionMasked == MotionEvent.ACTION_DOWN) {
// Defensive cleanup for new gesture
stopNestedScroll();
}
//与ViewGroup一样,需要进行安全性检测,避免View被恶意程序覆盖
if (onFilterTouchEventForSecurity(event)) {
//从注释来看,此处处理鼠标相关的输入,不用特意关注
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
//View存在onTouchListener时,onTouchListener优先消费
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
result = true;
}
//然后才是View调用onTouchEvent消费事件
//View的onTouchEvent函数,会根据事件的类型进行相应的处理
if (!result && onTouchEvent(event)) {
result = true;
}
}
//仍然是测试相关
if (!result && mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
// Clean up after nested scrolls if this is the end of a gesture;
// also cancel it if we tried an ACTION_DOWN but we didn't want the rest
// of the gesture.
// 事件处理完毕或ACTION_DOWN未处理, 清楚记录
if (actionMasked == MotionEvent.ACTION_UP ||
actionMasked == MotionEvent.ACTION_CANCEL ||
(actionMasked == MotionEvent.ACTION_DOWN && !result)) {
stopNestedScroll();
}
return result;
至此,View的事件分发流程分析完毕。
可以看出,由于View不需要继续将事件分发给Child View,
因此它需要管理的状态较少,事件处理的逻辑也比ViewGroup简单。
大致上来说,View处理事件的主要逻辑如下图所示: