TouchEvent的傳遞過程學習筆記

在學習自定義控件時,發現SDK中對touch event的描述比較模糊,因此本身寫了個demo並結合源代碼測試了一下java

在View類中,處理TouchEvent的方法有:dispatchTouchEvent和onTouchEvent函數

在ViewGroup類中處理TouchEvent的方法有:ViewGroup、onInterceptTouchEvent和onTouchEvent佈局

測試佈局模型是:學習

<MyViewGroup>
    <MyView />
</MyViewGroup>

當點擊View的時候測試

狀況一:若是全部的處理函數都返回false,TouchEvent的傳遞路徑是:spa

1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN
2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN
3) View.dispatchTouchEvent----------------------ACTION_DOWN
4) View.onTouchEvent----------------------------ACTION_DOWN
5) ViewGroup.onTouchEvent-----------------------ACTION_DOWN

並且只會受到ACTION_DOWN事件,不會收到ACTION_UP事件或者其它後續事件code

狀況二:MyView的onTouchEvent返回true,其它都返回false時,結果跟狀況一同樣xml

1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN
2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN
3) View.dispatchTouchEvent----------------------ACTION_DOWN
4) View.onTouchEvent----------------------------ACTION_DOWN
5) ViewGroup.onTouchEvent-----------------------ACTION_DOWN

狀況三:MyView的onTouchEvent和dispatchTouchEvent都返回true,其它返回false事件

1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN
2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN
3) View.dispatchTouchEvent----------------------ACTION_DOWN
4) View.onTouchEvent----------------------------ACTION_DOWN

你會發現ViewGroup的onTouchEvent不會收到消息,可是仍是收不到ACTION_UP事件get

狀況四:MyView的onTouchEvent和dispatchTouchEvent都返回true,MyViewGroup的dispatchTouchEvent也返回true的時候:

1) ViewGroup.dispatchTouchEvent-----------------ACTION_DOWN
2) ViewGroup.onInterceptTouchEvent--------------ACTION_DOWN
3) View.dispatchTouchEvent----------------------ACTION_DOWN
4) View.onTouchEvent----------------------------ACTION_DOWN
1) ViewGroup.dispatchTouchEvent-----------------ACTION_UP
2) ViewGroup.onInterceptTouchEvent--------------ACTION_UP
3) View.dispatchTouchEvent----------------------ACTION_UP
4) View.onTouchEvent----------------------------ACTION_UP

這時候就能收到ACTION_UP事件

ViewGroup dispatchTouchEvent(event)傳遞的主要邏輯的僞碼:

private View mMotionTarget;//保存真正處理響應的View
if (action == MotionEvent.ACTION_DOWN) //ACTION_DOWN事件
{
    if (mMotionTarget != null) {
        mMotionTarget = null;
    }
    if (!onInterceptTouchEvent()){ //若是攔截方法返回false,即不攔截
        for (allChild){ //循環全部子View或者ViewGroup
            if (child.dispatchTouchEvent()){ //若是child的dispatchTouchEvent返回true,即處理了事件
                mMotionTarget = child;
                return true; //若是child處理的消息,則直接返回true
            }
        }
    } else { //若是攔截方法返回true,即攔截此事件
        不把此事件傳遞給child,即child將不會收到此事件
    }
}

if (mMotionTarget == null){
    //調用本身的onTouchEvent方法
    //兩種狀況會走這個分支:1)ACTION_DOWN事件,child都返回false
    //2)後續事件,而且以前的ACTION_DOWN事件,child都返回false
    return onTouchEvent();
}

//如下是後續事件的處理過程
if (onInterceptTouchEvent()){ //若是事件被攔截
    mMotionTarget.dispatchTouchEvent(ACTION_CANCEL);//給目標child發送cancel事件
    return true;//直接返回
} else {//事件沒有被攔截
    return mMotionTarget.dispatchTouchEvent();//把事件交給child處理
}

View的dispatchTouchEvent(event)僞碼很簡單:

return onTouchEvent();


由此能夠看出,要想收到ACTION_DOWN的後續事件的條件是路徑上的全部dispatchTouchEvent都得返回true

而且本身的onTouchEvent得返回true,並且路徑上沒有攔截器攔截事件

相關文章
相關標籤/搜索