Android中View的事件分發(fā)機制

一個事件的產(chǎn)生總是從Activity開始到真正消費這個事件的View結(jié)束。

ViewGroup的事件分發(fā)

Activity包含了DecorView,DecorView是一個ViewGroup,我們從ViewGroup開始,一個事件通過dispatchTouchEvent到達ViewGroup之后,看看該ViewGroup是否攔截了此次事件(攔截的事件主要為Action.KEY_DOWN),如果攔截了此次事件則,該事件有該ViewGroup自己消費即調(diào)用自身的onTouchEvent,如果沒有攔截此次事件則遍歷自己的子類,并調(diào)用子類的dispathTouchEvent,若子類dispatchTouchEvent返回值均為false即子類中沒有View處理此次的事件,則該事件有自己處理。若子類中有View對此次的事件進行了消費,則記錄這個View。該View作為消費此Action.KEY_DOWN事件的消費者。于此同時不在進行下一步的事件分發(fā)。

View的事件分發(fā)

對于View來說,他是一般的事件消費者,他一般不進行事件的分發(fā),也就是說他一般不進行dispatchTouchEvent的重寫,默認的dispatchTouchEvent就是調(diào)用了View的onTouchEvent:

public boolean dispatchTouchEvent(MotionEvent event) {
  return onTouchEvent(event);
}

整個ViewGroup的繪制過程用代碼描述為以下:

    View mTarget=null;//保存捕獲Touch事件處理的View
    public boolean dispatchTouchEvent(MotionEvent ev) {
        //....其他處理,在此不管
        if(ev.getAction()==KeyEvent.ACTION_DOWN){
            //每次Down事件,都置為Null
            if(!onInterceptTouchEvent()){
            mTarget=null;
            View[] views=getChildView();
            for(int i=0;i<views.length;i++){
                if(views[i].dispatchTouchEvent(ev))
                    mTarget=views[i];
                    return true;
            }
          }
        }
        //當子View沒有捕獲down事件時,ViewGroup自身處理。這里處理的Touch事件包含Down、Up和Move
        if(mTarget==null){
            return super.dispatchTouchEvent(ev);
        }
        //...其他處理,在此不管
        if(onInterceptTouchEvent()){
         //...其他處理,在此不管    
        }
        //這一步在Action_Down中是不會執(zhí)行到的,只有Move和UP才會執(zhí)行到。
        return mTarget.dispatchTouchEvent(ev);
    }

ViewGroup的事件分發(fā)只攔截ACTION_DOWN事件,不管是點擊事件還是滑動事件即不管是ACTION_DOWN、ACTION_MOVE、ACTION_UP都是從ACTION_DOWN開始的,因此只要攔截了ACTION_DOWN事件,ViewGroup的子View便不再會收到此次的事件。這里為什么不攔截其他事件呢?如果我們以及直到了子View中有一個View消費了此次事件,即ACTION_MOVE應當被傳遞給他,也就是說如果mTarget不為空的時候我們應調(diào)用mTarget進行下一步的事件分發(fā)。

舉個栗子:

image.png

假如說有一個ViewGroup中有A、B兩個子View,想象此時用戶手指點擊了A但并未松手,而是將手指滑動到了B。首先來看前半部分,用戶點擊了A,此時相當于A消費了ACTION_DOWN事件,對于ViewGroup來說,mTarget=A,這個時候用戶將手指劃出了A到了B,并在B上面滑動,那么對于系統(tǒng) 產(chǎn)生的這個滑動的事件ACTION_MOVE是由誰來處理呢?我們可以從日常操作APP比如滑動切換的ViewPager的時候想到,這個事件是由A來處理的,為什么?對于ViewGroup來說這個ACTION_DOWN事件沒有結(jié)束,他的mTarget對象依然是存在的,然而它只攔截和分發(fā)ACTION_DOWN事件,對于mTarget不為空的情況則直接將事件交由mTarget來處理了。直到ACTION_UP事件被mTarget處理完,等到下一次ACTION_DOWN傳到ViewGroup的時候此時的mTarget就變成空的了。

?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

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

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