「这是我参与11月更文挑战的第25天,活动详情查看:2021最后一次更文挑战」
1. View.dispatchTouchEvent()
View的关键方法是onTounchEvent(),是事件处理的主要步骤,也是事件分发流程的最后步骤。View也有dispatchTounchEvent(),在方法中主要是确定事件该交由谁来处理,是onTouchEvent()处理还是onTouchListener处理
- 判断当前事件是否要求传递给已经获取焦点的View
public final boolean dispatchPointerEvent(MotionEvent event) {
if (event.isTouchEvent()) {
return dispatchTouchEvent(event);
} else {
return dispatchGenericMotionEvent(event);
}
}
- 判断当前View是否可以接收事件的判断,如果可以则进行分发,事件分发有3个步骤: (1) 首先是handleScrollBarDragging(),处理滚动条事件的,该方法只处理来自鼠标的事件,因此一般情况下都返回false
(2) 然后是OnTouchListener处理,并记录处理结果,如果我们在onTouchListener中返回了true,即消费了事件的话,那么该事件将不再进入View.onTouchEvent()。也就意味着无法处理点击、长按等事件处理了。
(3) 两者是否已经消费了事件,如果是的话则不再将事件分发给onTouchEvent(),否则再将事件交给onTouchEvent()去处理
if (onFilterTouchEventForSecurity(event)) {
if ((mViewFlags & ENABLED_MASK) == ENABLED && handleScrollBarDragging(event)) {
result = true;
}
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;
}
}
2. View.onTouchEvent()
- (1) clickable:先判断当前View是否允许点击
- (2) 判断View是否是处于不可用状态,如果不可用的话则直接将是否可点击作为是否消费事件返回
- (3) 将事件交给代理去处理,如果代理处理了事件,那么事件分发到此结束。否则就继续往下,使用默认的实现对事件进行处理
public boolean onTouchEvent(MotionEvent event) {
...
// (1)
final boolean clickable = ((viewFlags & CLICKABLE) == CLICKABLE
|| (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)
|| (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE;
// (2)
if ((viewFlags & ENABLED_MASK) == DISABLED
&& (mPrivateFlags4 & PFLAG4_ALLOW_CLICK_WHEN_DISABLED) == 0) {
if (action == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
setPressed(false);
}
mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;
return clickable;
}
// (3)
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
...
return false;
}
3. 总结
- View负责事件消费事件处理
- 调用mOnTouchListener的onTouch
- 如果消费,直接返回true,否则,继续调用onTouchEvent方法
- 如果为启用的(enable),返回可点击(clickable),否则,调用mTouchDelegate的onTouchEvent
- 如果消费,直接返回true ,如果可点击(clickable), 进行事件流(ACTION_DOWN,ACTION_MOVE,ACTION_UP,ACTION_CANCEL)处理,返回true,否则返回false