View事件分發涉及的方法:onTouch、dispatchTouchEvent、onTouchEvent 。
ViewGroup事件分發涉及的方法:onTouch、dispatchTouchEvent、onTouchEvent 、onInterceptTouchEvent。
1. Button點擊事件響應流程
點擊Button --> 調用Button的dispatchTouchEvent -->調用TextView的dispatchTouchEvent方法
--> 調用View的dispatchTouchEvent方法,我們來看下View的dispatchTouchEvent方法內部
public boolean dispatchTouchEvent(MotionEvent event) {
if (!onFilterTouchEventForSecurity(event)) {
return false;
}
// 1. 設置過監聽,2.按鈕是ENABLED(默認爲true) 3.onTouch方法返回true
if (mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED && mOnTouchListener.onTouch(this, event)) {
return true;
}
return onTouchEvent(event);
}
第一種情況:當1和2爲真的時候,纔會執行3,當3中onTouch方法返回true的時候,dispatchTouchEvent返回true,
也就標誌着此事件被消耗。
第二種情況:當1和2爲真的時候,纔會執行3,當3中onTouch方法返回false的時候,調用onTouchEvent方法,
下面我們看看這個方法內部。
public boolean onTouchEvent(MotionEvent event) {
final int viewFlags = mViewFlags;
if ((viewFlags & ENABLED_MASK) == DISABLED) {
return (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
}
if (mTouchDelegate != null) {
if (mTouchDelegate.onTouchEvent(event)) {
return true;
}
}
// 判斷View是否是可點擊的,如果可點擊則UP之後會執行到performClick方法,此方法中會調用onClick方法處理相應邏輯,並返回true
// 如果不是可點擊的,則始終會返回false
if (((viewFlags & CLICKABLE) == CLICKABLE ||(viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
switch (event.getAction()) {
case MotionEvent.ACTION_UP:
boolean prepressed = (mPrivateFlags & PREPRESSED) != 0;
if ((mPrivateFlags & PRESSED) != 0 || prepressed) {
boolean focusTaken = false;
if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
focusTaken = requestFocus();
}
if (!mHasPerformedLongPress) {
removeLongPressCallback();
if (!focusTaken) {
if (mPerformClick == null) {
mPerformClick = new PerformClick();
}
if (!post(mPerformClick)) {
performClick();
}
}
}
}
break;
case MotionEvent.ACTION_DOWN:
...
break;
...
case MotionEvent.ACTION_CANCEL:
break;
...
case MotionEvent.ACTION_MOVE:
break;
}
return true;
}
return false;
}
下面我們簡單的看一下performClick這個方法吧
public boolean performClick() {
sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
if (mOnClickListener != null) {
playSoundEffect(SoundEffectConstants.CLICK);
//執行點擊事件業務邏輯,並返回true消費此事件
mOnClickListener.onClick(this);
return true;
}
return false;
}
2. ImageView點擊事件響應流程
ImageView和Button的區別是:ImageView默認是不可點擊的,也就是說如果執行到onTouchEvent方法,此方法會一直返回false,也就是dispatchTouchEvent方法返回false,此事件就不會被消耗就只會執行一次ActionDown操作.
當然,如果想對ImageView添加點擊事件,可以設置它的clickable屬性。
注意:官方文檔對dispatchTouchEvent的返回值的解釋是:True if the event was handled by the view, false otherwise。
我們可以簡單的理解爲如果返回true,就說明它需要處理這個事件,就讓它接收所有的觸屏事件,否則,說明它不用處理,也就不讓它接收後續的觸屏事件了。
如果你感興趣,請繼續閱讀《Android View、ViewGroup 事件分發機制(二)》