天天看點

Android開發中處理TouchEvent的林林總總

最近在開發過程中遇到了有關處理和攔截點選事件的邏輯問題,在這裡稍微進行一下總結~

①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,請大家務必注意!

繼續閱讀