Android 事件傳遞總結
Android 事件傳遞總結
首先 吐槽下17年的北京市場,簡直無法生存了,為了18年不被淘汰,只能不停的催眠自己,我愛學習,我愛鑽研,我更愛擼程式碼:
- 參考郭神的部落格 Android事件分發機制完全解析,帶你從原始碼的角度徹底理解
- View的事件分發處理過程
- ViewGroup 的事件分發過程
View事件分發過程詳解
首先單獨給一個View新增一個點選事件一般我們使用
button.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Log.d("TAG", "onClick execute");
}
});
或者還可以使用setOnTouchListener方法
button.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
Log.d("TAG", "onTouch execute, action " + event.getAction());
return false;
}
});
現在,給一個控制元件,添加了兩次監聽事件。
onTouch是優先於onClick執行的,並且onTouch執行了兩次,一次是ACTION_DOWN,一次是ACTION_UP(你還可能會有多次ACTION_MOVE的執行,如果你手抖了一下)。因此事件傳遞的順序是先經過onTouch,再傳遞到onClick。
並且 onTouch方法是有返回資料的。現在我預設返回的是false,如果我把此方法返回的資料為 true, 那麼onlick方法並不會執行。
只要你觸控到了任何一個控制元件,就一定會呼叫該控制元件的dispatchTouchEvent方法。那當我們去點選按鈕的時候,就會去呼叫View類裡的dispatchTouchEvent方法
public boolean dispatchTouchEvent(MotionEvent event) {
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED &&
mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
原始碼中,dispatchTouchEvent 會走一個判斷,
判斷為true的話,dispatchTouchEvent方法會返回 true,
如果判斷走flase的話,會執行 onTouchEvent(event)方法
一共是三個判斷,我們一個一個分析、
第一個判斷:mOnTouchListener != null
public void setOnTouchListener(OnTouchListener l) {
mOnTouchListener = l;
}
看到原始碼,在我們給一個view新增點選事件的時候mOnTouchListener就被賦值了,此判斷為true
第二個判斷:(mViewFlags & ENABLED_MASK) == ENABLED
這個是 判斷當前點選的控制元件是否是enabled ,因為所有的控制元件預設為enabled(是否可點選),所以這個恆定為true;
第三個判斷: mOnTouchListener.onTouch(this, event)
其實就是去回撥控制元件註冊touch事件時的onTouch方法。也就是說如果我們在onTouch方法裡返回true,就會讓這三個條件全部成立,從而整個方法直接返回true。如果我們在onTouch方法裡返回false,就會再去執行onTouchEvent(event)方法。
結論:
首先在dispatchTouchEvent中最先執行的就是onTouch方法,因此onTouch肯定是要優先於onClick執行的,而如果在onTouch方法裡返回了true,就會讓dispatchTouchEvent方法直接返回true,不會再繼續往下執行。而列印結果也證實瞭如果onTouch返回true,onClick就不會再執行了。
所以我們可以判斷出,onClick的執行肯定在onTouchEvent(event)方法中
寫到這裡,一個View的事件傳遞流程,應該很清楚了。
面試:
1. onTouch和onTouchEvent有什麼區別?
從原始碼中可以看出,這兩個方法都是在View的dispatchTouchEvent中呼叫的,onTouch優先於onTouchEvent執行。如果在onTouch方法中通過返回true將事件消費掉,onTouchEvent將不會再執行。
ViewGroup事件分發過程詳解
當你點選了某個控制元件,首先會去呼叫該控制元件所在佈局的dispatchTouchEvent方法,然後在佈局的dispatchTouchEvent方法中找到被點選的相應控制元件,再去呼叫該控制元件的dispatchTouchEvent方法。