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