Android的事件傳遞機制

事件分發(fā)過程由下列三個方法共同完成:

  • boolean dispatchTouchEvent (MotionEvent event)
    用來進(jìn)行事件的分發(fā)。如果事件可以傳遞給當(dāng)前View,那么此方法一定會被調(diào)用。返回結(jié)果受當(dāng)前View的onTouchEvent和子View的dispatchTouchEvent返回結(jié)果的影響,表示是否消耗當(dāng)前事件。
  • boolean onInterceptTouchEvent (MotionEvent event)
    在上述方法內(nèi)部調(diào)用,用來判斷是否攔截某個事件。如果當(dāng)前View攔截了某個事件,那么在同一個事件序列過程中,該方法不會被再次被調(diào)用。返回結(jié)果表示是否攔截當(dāng)前事件。
  • boolean onTouchEvent (MotionEvent event)
    在dispatchTouchEvent方法中調(diào)用,用來處理當(dāng)前事件。其中,MotionEvent.ACTION_UP時會調(diào)用performClick方法,即mOnClickListener.onClick(this)方法。返回結(jié)果表示是否消耗當(dāng)前事件,如果不消耗,則在同一個事件序列過程中,當(dāng)前View無法再次接收到事件。

偽代碼表示事件傳遞規(guī)則:

ViewGroup的分發(fā)過程
public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume = false;
    if (onInterceptTouchEvent(event)) {
        consume = super.dispatchTouchEvent(event);
    } else {
        consume = child.dispatchTouchEvent(event);
        if (!consume) {
            consume = super.dispatchTouchEvent(event);
        }
    }
    return consume;
}
View的分發(fā)過程
public boolean dispatchTouchEvent(MotionEvent event) {
    boolean consume = false;
    if (mOnTouchListener.onTouch(this, event)) {
        consume = true;
    } else {
        consume = onTouchEvent(event);
    }
    return consume;
}

demo效果


默認(rèn)情況.png
父容器攔截事件.png
子View onTouchEvent返回false.png

結(jié)論:

  • 事件處理優(yōu)先級比較:OnTouchListener.onTouch > onTouchEvent > OnClickListener.onClick。
  • 同一個事件序列是指從手指觸摸屏幕的那一刻起,到手指離開屏幕的那一刻結(jié)束,在這個過程中所產(chǎn)生的一系列事件。這個事件序列:down -- 若干個move -- up。
  • 事件傳遞流程:Activity -> Window -> View。
  • 當(dāng)一個View攔截一個事件后,那么這個事件序列都只能由它來處理,并且它的onInterceptTouchEvent方法不會再被調(diào)用。
  • 正常情況下,一個事件序列只能被一個View攔截且消耗(特殊情況:View通過onTouchEvent將需要自己處理的事件強行傳遞給其他View)。
  • 某個View一旦開始處理事件,如果它不消耗ACTION_DOWN事件(onTouchEvent返回false),那么同一事件序列中的其他事件都不會交給它來處理,而是重新交給它的父元素處理。
  • 如果View不消耗ACTION_DOWN以外的其他事件,那么點擊事件會消失,此時父元素的onTouchEvent并不會被調(diào)用,并且當(dāng)前View可以持續(xù)收到后續(xù)事件,最終這些點擊事件交給Activity處理。
  • ViewGroup默認(rèn)不攔截任何事件。
  • View沒有onInterceptTouchEvent方法。
  • View的onTouchEvent默認(rèn)都會消耗事件(返回true),除非它是不可點擊的。

應(yīng)用:滑動沖突的解決

  • 外部攔截法:重寫父容器的onInterceptTouchEvent方法,判斷是否需要攔截
  • 內(nèi)部攔截法:重寫子View的dispatchTouchEvent方法,判斷是否消耗掉事件
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容