Android View、ViewGroup 事件分發機制(一)

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 事件分發機制(二)》


Demo下載請猛戳

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章