自定義 MyButton 重寫 dispatchTouchEvent 和 onTouchEvent,並設置 OnTouchListener。日誌顯示 onTouchEvent 先於 dispatchTouchEvent 輸出,似乎違背「分發在前、處理在後」的認知。
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
// 日誌打印
return super.dispatchTouchEvent(event); // 調用父類實現
}
@Override
public boolean onTouchEvent(MotionEvent event) {
// 日誌打印
return super.onTouchEvent(event);
}
// Activity 中
button.setOnTouchListener((v, event) -> false); // 返回 false
View.dispatchTouchEvent(event)
│
├─ 1. OnTouchListener.onTouch() → 返回 true 則消費事件,流程結束
│
├─ 2. onTouchEvent(event) → 返回 true 則消費事件
│ ├─ 手勢檢測、長按等
│ └─ performClick() → OnClickListener.onClick()
│
└─ 返回結果(true/false)
查看 Android 源碼 View.dispatchTouchEvent 簡化邏輯:
public boolean dispatchTouchEvent(MotionEvent event) {
// ...
if (onTouchListener != null && onTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event); // 直接調用 onTouchEvent!
}
因此:
1. 進入 MyButton.dispatchTouchEvent(子類重寫)
2. 打印「dispatchTouchEvent: DOWN」日誌
3. 調用 super.dispatchTouchEvent(event)(父類 View 實現)
4. 父類內部調用 onTouchEvent(event)
5. 進入 MyButton.onTouchEvent(子類重寫)
6. 打印「onTouchEvent: DOWN」日誌
7. 返回層層回溯
8. 回到子類 dispatchTouchEvent,打印「==========================」分隔符
9. 返回結果
// 按下時
MyButton|onTouchEvent|event:DOWN // 步驟 5-6:父類 dispatch 內部調用 onTouchEvent
MyButton|dispatchTouchEvent|event:DOWN // 步驟 2-3:子類 dispatch 打印,然後調用 super
========================== // 步驟 8:子類 dispatch 打印分隔符
MyButton|onTouchEvent|event:DOWN // 步驟?:可能是 performClick 內部再次調用?或日誌重複
第三行 onTouchEvent 可能來自 performClick() 觸發的再次分發,或 OnTouchListener 返回 false 導致的複雜流程。
dispatchTouchEvent 時,日誌打印位置決定觀察順序:若在 super.dispatchTouchEvent() 前打印,則顯示「dispatch 先」;若在後打印,則顯示「onTouchEvent 先」。Log.d("BEFORE super"); super.dispatchTouchEvent(event); Log.d("AFTER super");true = 消費事件,阻止向上傳遞;false = 向父 View 傳遞。onInterceptTouchEvent,直接 dispatchTouchEvent → onTouchEvent。日誌顯示 onTouchEvent 先於 dispatchTouchEvent 打印,是因為子類 dispatchTouchEvent 中的日誌語句位於 super.dispatchTouchEvent() 調用之後,而父類 dispatchTouchEvent 內部同步調用了 onTouchEvent。這不代表事件分發機制改變,僅是代碼執行順序與日誌打印位置造成的視覺誤導。理解 View.dispatchTouchEvent 源碼邏輯,即可釐清真實調用鏈。