View 的 dispatchTouchEvent OnTouchListener onTouchEvent OnClickListener 的聯(lián)系
通過看源碼來分析 View 事件分發(fā)過程(下面的代碼是精簡過后的)
下面僅針對 View ,ViewGroup 會重寫 dispatchTouchEvent,所以會不同惕澎。
public boolean dispatchTouchEvent(MotionEvent event) {
boolean result = false;
if (onFilterTouchEventForSecurity(event)) {
ListenerInfo li = mListenerInfo; // 包含了很多的監(jiān)聽器(包括:OnTouchListener灯蝴,OnClickListener...)
if (li != null && li.mOnTouchListener != null
&& (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) { // 這里點調(diào)用了 OnTouchListener.onTouch -> true 則 result = true
result = true;
}
// result = true 則不走 onTouchEvent 了
if (!result && onTouchEvent(event)) {
result = true;
}
}
return result;
}
可以看到 dispatchTouchEvent :
- 先調(diào)用 OnTouchListener.onTouch
- 如果 onTouch 返回 false 則
- 調(diào)用 onTouchEvent(event)
目前沒有看到 onClick 的身影,其實是在 onTouchEvent 中:
下面的代碼只是看下源碼 「確實是在 ACTION_UP 中調(diào)用了 onClick 」
public boolean onTouchEvent(MotionEvent event) {
if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {
switch (action) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {
if (!focusTaken) {
if (!post(mPerformClick)) {
performClick(); // 經(jīng)過一些判斷后調(diào)用 performClick
}
}
}
...
break;
...
}
}
}
public boolean performClick() {
final boolean result;
final ListenerInfo li = mListenerInfo;
if (li != null && li.mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
li.mOnClickListener.onClick(this); // 調(diào)用 OnClickListener.onClick
result = true;
} else {
result = false;
}
return result;
}
在 onTouchEvent 中的 ACTION_UP 中判斷一些條件是否滿足調(diào)用點擊事件聂渊,如果滿足并且點擊事件監(jiān)聽 mOnClickListener 不為 null 才去調(diào)用 OnClickListener.onClick
所以先后循序:
dispatchTouchEvent => OnTouchListener => onTouchEvent => OnClickListener
為什么是在 ACTION_UP 中判斷呢差购?
- 只有在抬起的時候才能確定這個事件會不會是 長點擊 還是 普通的點擊
- 只能在其他操作完成之后才能得出是否需要觸發(fā) 點擊事件
最后一張流程圖總結(jié):
Android View 的事件分發(fā).png