1. 程式人生 > >細說Android事件傳遞機制(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)

細說Android事件傳遞機制(dispatchTouchEvent、onInterceptTouchEvent、onTouchEvent)

本文背景:前些天用到了之前寫的自定義圖片文字複合控制元件,在給他設定監聽時遇到了麻煩。雖然最後解決了問題,但發現在不重寫LinearLayout的onInterceptTouchEvent時,子ImageView、子TextView、父Linearlayout三者不同的屬性配置(android:clickable android:focuseable)會造成自定義控制元件onClick監聽失敗、或成功。複寫了父Linearlayout 的onInterceptTouchEvent時,監聽不受子圖片、子文字的屬性影響。為知其所以然,深入研究android的事件傳遞機制,記錄於此。

一、View的dispatchTouchEvent和onTouchEvent

探討Android事件傳遞機制前,明確android的兩大基礎控制元件型別:View和ViewGroup。View即普通的控制元件,沒有子佈局的,如Button、TextView. ViewGroup繼承自View,表示可以有子控制元件,如Linearlayout、Listview這些。而事件即MotionEvent,最重要的有3個:(1)MotionEvent.ACTION_DOWN 按下View,是所有事件的開始(2)MotionEvent.ACTION_MOVE 滑動事件
(3)MotionEvent.ACTION_UP 與down對應,表示擡起
另外,明確事件傳遞機制的最終目的都是為了觸發執行View的點選監聽和觸控監聽: ******.setOnClickListener(new View.OnClickListener() {


@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Log.i(tag, "testLinelayout---onClick...");
}
});

*******.setOnTouchListener(new View.OnTouchListener() {

@Override
public boolean onTouch(View v, MotionEvent event) {
// TODO Auto-generated method stub

return false;

}
});
我們簡稱為onClick監聽和onTouch監聽,一般程式會註冊這兩個監聽。從上面可以看到,onTouch監聽裡預設return false。不要小看了這個return false,後面可以看到它有大用。 對於View來說,事件傳遞機制有兩個函式:dispatchTouchEvent負責分發事件,在dispatch***裡又會呼叫onTouchEvent表示執行事件,或者說消費事件,結合原始碼分析其流程。事件傳遞的入口是View的dispatchTouchEvent()函式: 01./** 02.* Pass the touch screen motion event down to the target view, or this 03.* view if it is the target. 04.* 05.* @param event The motion event to be dispatched. 06.* @return True if the event was handled by the view, false otherwise. 07.*/ 08.public boolean dispatchTouchEvent(MotionEvent event) { 09.if (mInputEventConsistencyVerifier != null) { 10.mInputEventConsistencyVerifier.onTouchEvent(event, 0); 11.} 12. 13.if (onFilterTouchEventForSecurity(event)) { 14.//noinspection SimplifiableIfStatement 15.ListenerInfo li = mListenerInfo; 16.if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED 17.&& li.mOnTouchListener.onTouch(this, event)) { 18.return true; 19.} 20. 21.if (onTouchEvent(event)) { 22.return true; 23.} 24.} 25. 26.if (mInputEventConsistencyVerifier != null) { 27.mInputEventConsistencyVerifier.onUnhandledEvent(event, 0); 28.} 29.return false; 30.} 找到這個判斷: if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnTouchListener.onTouch(this, event)) {
return true;
}
他會執行View的OnTouchListener.onTouch這個函式,也就是上面說的onTouch監聽。裡面有三個判斷,如果三個都為1,就會執行return true,不往下走了。而預設的onTouch監聽返回false,只要一個是false,就不會返回true。接著往下看,程式執行onTouchEvent: 1.if (onTouchEvent(event)) { 2.return true; 3.} onTouchEvent的原始碼比較多,貼最重要的: 01.if (!mHasPerformedLongPress) { 02.// This is a tap, so remove the longpress check 03.removeLongPres