最近在開發過程中遇到了有關處理和攔截點選事件的邏輯問題,在這裡稍微進行一下總結~
①Android處理TouchEvent的流程
首先來看一下跟Touch事件相關的三個方法:
public boolean dispatchTouchEvent(MotionEvent ev); //用來分派event
public boolean onInterceptTouchEvent(MotionEvent ev); //用來攔截event,ViewGroup可用,View不可用
public boolean onTouchEvent(MotionEvent ev); //用來處理event
舉例說明:
假設我們現在擁有一個Textview,一個LinerLayout,TextView位于LinerLayout中,布局大體檔案如下:
<LinerLayout>
<TextView>
</TextView>
</LinerLayout>
當我們點選螢幕時,觸發一個TouchEvent,這個事件的處理流程是:
(1)首先由頂層的View也就是Activity擷取到,由Acticity的dispatchTouchEvent進行分派,預設将其傳遞至Activity的onInterceptTouchEvent,傳回值為super.dispatchTouchEvent;
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
(2)Activity的onInterceptTouchEvent擷取到分派函數分派的TouchEvent,決定是否将其攔截在這裡。
public boolean onInterceptTouchEvent (MotionEvent event) {
return super.onInterceptTouchEvent(ev);
}
如果進行攔截(傳回值為True),就不繼續分發,同時将調用Acticity的onTouchEvent;如果不進行攔截(傳回值為False,為預設操作),則将該Event下發至下一個View的dispatchTouchEvent;
(3)如果Event在上一步沒有被攔截,此時調用LinerLayout的dispatchEvent和onInterceptTouchEvent;
(4)如果Event在上一步沒有被攔截,此時調用TextView的dispatchEvent,由于TextView不是ViewGroup,則直接調用TextView的onTouchEvent;
(5)TextView的onTouchEvent決定是否消費(consume)這個Event,如果傳回值為True,則該Event終止,流程結束;否則将其傳回上一級的onTouchEvent(此為預設操作);
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}
(6)如果TextView的onTouchEvent沒有消費這個Event,那麼由LinerLayout的onTouchEvent處理該事件;
(7)如果LinerLayout的onTouchEvent沒有消費這個Event,那麼由Acticity的onTouchEvent處理該事件,流程結束。
需要注意的是:
(1)如果TextView的Clickable屬性為True,那麼TextView就會消費掉TouchEvent,不再進行回傳。
(2)每一個dispatchTouchEvent會記錄事件是否被成功處理。如果dispatchTouchEvent檢測到該層的onTouchEvent被調用了,那麼當下一個事件傳遞來時,dispatchTouchEvent會自動将事件分派給本層的onTouchEvent而不向下分發,這一點會導緻很多BUG,請大家務必注意!