android中的事件傳遞機制(1)

最近由於項目的需要博主研究了一下事件傳遞機制,在網上翻閱了很多的解釋,看的也是雲裏霧裏的,不過經過梳理和觀察源碼終於把事件傳遞機制研究明白了

將分爲三部分博客來記錄android事件傳遞機制
在寫之前推薦幾個比較好的事件傳遞機制的博客,有助於大家理解
1.關於view什麼時候會調用onClick和ontouch監聽事件
2事件傳遞和消費(不過這個博客寫的有部分錯誤,博主將會在後面給大家解釋哪裏出現錯誤)
3事件的三種類型和調用順序(文章中有部分問題,僅用於更好的理解後面內容)

前言:如果對事件傳遞沒有一點了解的建議先看一下1和2的微博,如果有所瞭解的人可直接看本文,肯定讓你深刻的理解事件傳遞

看過了這麼多文字想必你還是有點蒙的,而且很多文章都是相互衝突的,所以我們最好的辦法就是去看源碼.
1.首先我先分析一下android中的控件的結構,
activity作爲一個活動中包含一個window窗口,window下可以放多個ViewGroup,viewGroup中可以放多個view
2.但是我們通過源碼可以看出ViewGroup也是繼承View的

public abstract class ViewGroup extends View implements ViewParent, ViewManager {

3.那我就從view開始看起,通過看源碼可以發現view中包含兩個處理時間的方法,
dispatchTouchEvent(MotionEvent event)onTouchEvent(MotionEvent event)
4.我們知道事件傳遞機制都是先調用dispatchTouchEvent()方法,所有我們看一下源碼

   public boolean dispatchTouchEvent(MotionEvent event) {
        if (event.isTargetAccessibilityFocus()) {
            if (!isAccessibilityFocusedViewOrHost()) {
                return false;
            }
            event.setTargetAccessibilityFocus(false);
        }

        boolean result = false;

        if (mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onTouchEvent(event, 0);
        }

        final int actionMasked = event.getActionMasked();
        if (actionMasked == MotionEvent.ACTION_DOWN) {
            stopNestedScroll();
        }

        if (onFilterTouchEventForSecurity(event)) {
            ListenerInfo li = mListenerInfo;
            if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }
        }

        if (!result && mInputEventConsistencyVerifier != null) {
            mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
        }
        if (actionMasked == MotionEvent.ACTION_UP ||
                actionMasked == MotionEvent.ACTION_CANCEL ||
                (actionMasked == MotionEvent.ACTION_DOWN && !result)) {
            stopNestedScroll();
        }

        return result;
    }

前幾行是關於判讀view是否有焦點的代碼我們不用看,主要看其中這段代碼

 if (li != null && li.mOnTouchListener != null
                    && (mViewFlags & ENABLED_MASK) == ENABLED
                    && li.mOnTouchListener.onTouch(this, event)) {
                result = true;
            }

            if (!result && onTouchEvent(event)) {
                result = true;
            }

從這段代碼中可以看的出來view是先判讀用戶是否綁定了OnTouchListener,如果綁定了則調用用戶定義的onTouch方法,並且把返回值作爲最終結果返回。如果沒有定義就調用view中的onTouchEvent方法並返回結果。(在onTouch方法中會調用點擊事件處理)
5.看過view的代碼你應該知道了view中dispatchTouchEvent()onTouchEvent()的關係了吧,是前者調用了後者。
6.接下來我們看一下ViewGroup中的代碼,這個要比view要複雜一些,通過看源碼我們可以看出來ViewGroup繼承View並且重寫了
dispatchTouchEvent()
;和增加了OnInterceptTouchEvent();
7.還是首先我們看一下dispatchTouchEvent()中的代碼
由於該方法的代碼過長我就不粘貼了,大家可以看自己的android源碼,在第1929行就是該方法,這個方法先是在1960行調用了
onInterceptTouchEvent
方法,並記錄返回值intercepted ,如果intercepted==flase那麼將調用ViewGroup中的所有子View的dispatchTouchEvent()。一但有某一個view的方法返回true則ViewGroup的dispatchTouch()返回true。
8.從這一點我們就能知道了onInterceptTouchEvent是怎麼進行屏蔽的了,onInterceptTouchEvent返回爲true時則不會調用子view的dispatchTouch,只調用viewGroup的super.onTouchEvent()。
9.那麼什麼時候viewGroup的子view的dispatchTouch()會返回true?剛纔我們在看view的代碼的時候知道,當view中的onTouchEvent返回true時分發函數也會返回true。
10.從這些代碼中我們就能理解了,時間是如何向下傳遞的了。那麼如果沒有子view呢?在2372行代碼中我們能知道,如果沒有子view則ViewGroup調用super.dispatchTouch()

注:viewGroup中的onInterceptTouchEvent默認返回的是false,也就是默認是都要給子view進行事件傳遞的,但是有些繼承了viewGroup並且重寫了該方法的就要具體問題具體分析了。

下一期我講述事件傳遞到最低端後是否會回傳給上層控件

發佈了31 篇原創文章 · 獲贊 7 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章