一個事件的產(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ā)。
舉個栗子:

假如說有一個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就變成空的了。