Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android開發 >> 關於android開發 >> Android事件分發機制源碼分析

Android事件分發機制源碼分析

編輯:關於android開發

Android事件分發機制源碼分析


小小感慨一下,做android有一段時間了,一直以來都是習慣整理筆記存到有道筆記上,沒有寫博客的習慣。以後逐步分類整理出來,也算“復習”一遍了 - _ - 。

android的事件分發相關的方法有三個:

1.public booleandispatchTouchEvent(MotionEvent ev)

2.public boolean onInterceptTouchEvent(MotionEvent ev)

3.public booleanonTouchEvent(MotionEvent event)

第一個方法表示是否分發事件,第二個方法表示是否攔截事件(僅僅ViewGroup有這個方法,View沒有),第三個方法表示是否消費事件。

分析源碼之前,我們先總結一下事件分發的規律,或者說上面3個方法的使用方法:

①當TouchEvent發生時,首先Activity將TouchEvent傳遞給最頂層的View,一般是一個ViewGroup。TouchEvent最先到達最頂層 view 的 dispatchTouchEvent ,然後由dispatchTouchEvent 方法進行分發,返回true則不分發,全部事件都交給dispatchTouchEvent 處理,如果dispatchTouchEvent返回 false ,則view以及它的子view都接收不到後續事件,如果調用super.dispatchTouchEvent,則交給interceptTouchEvent 處理。

②如果 interceptTouchEvent 返回 true ,也就是攔截掉了,則後續事件交給它的 onTouchEvent 來處理interceptTouchEvent 不再處理(如果手拿起來在重新點擊,down事件還會走一次,後面的move和up不走了),如果onTouchEvent不處理,事件原路返回,後續事件就不交給這個view了,如果 interceptTouchEvent 返回 false 或者調用super.interceptTouchEvent,那麼後續事件仍然經過interceptTouchEvent 處理,但是不經過onTouchEvent。沒有interceptTouchEvent方法的普通view不考慮這個方法,其他規律相同

③對於onTouvhEvent返回true表示消費事件,false表示不消費,調用super.onTouchEvent時分兩種情況,對於ViewGroup等可以放子View的來說不消費事件,對於不能放子View的View來說消費事件。不消費事件時事件到達最底層的view後會回傳,只走onTouchEvent,可能被上層View消費

如果你僅僅是關心這幾個方法的使用,然後自己自定義view,那看到這裡應該就沒神馬問題了,反正我知道這幾個方法會對事件分發造成什麼影響了,至於為啥我就不關心了得意

但是作為一個積極學習高素質的程序猿來說,我們不僅要弄明白怎麼用,還要明白為什麼會出現這些情況(此處應有掌聲)。我們就按照上面的三點逐點分析。

 

首先我們看第一點:dispatchTouchEvent。這個方法返回false表示事件不分發,那麼可以理解為這個view以及子view都不會消費事件,那後續事件就不會在給你了,反正給了你你也不消費嘛,干嘛還給你,這個很好理解,代碼實現是把所有消耗事件的View都保存起來,所以不消費事件的View是不會即受到後續事件的,這部分代碼沒貼出來,參見ViewGroup代碼的第2213行調用addTouchTarget方法的代碼。按照常規來想,既然返回false表示不消費事件,那麼返回true就應該是消費事件了吧?NO NO NO,too young to simple。如果你寫demo試試就會發現dispatchTouchEvent方法一直走,但是事件卻沒有分發下去,子view收不到事件,只有返回值是super.dispatchTouchEvent才能把事件分發下去。。。納尼,這是什麼鬼發火,不按套路出牌啊。好吧,這種情況只能翻源碼了。我們以android6.0(API Level 23)的源碼為准進行分析。

下面這段代碼是摘自ViewGroup的dispatchTouchEvent方法,在2167行是取到第i個子view。然後到2197行,這裡調用了一個方法,將上面取到的第i個子view作為參數之一傳了過去。

\

下面這段代碼是剛才說到的在dispatchTouchEvent中調用的這個方法,看第2553行,當child不為空的時候,調用了child的dispatchTouchEvent(具體會走到2553或者2575行,他們本質上是一樣的,區別就是對傳過來的MotionEvent進行了一個split操作,具體做了啥沒去深究。有知道它們區別的小伙伴可以留言賜教)。到這裡是不是有一種豁然開朗的感覺呢?得意ViewGroup之所以能將事件分發給子view是因為在dispatchTouchEvent中又調用了子view的事件分發方法,如果你在ViewGroup的dispatchTouchEvent方法中只返回true而不返回super.dispatchTouchEvent,那麼子view的事件分發的方法將不會調用,子view就拿不到事件。明白了吧,我覺得我說的還是挺清楚的生氣。中間我們忽略了其他不相關的代碼,如果你想深入了解,可以再去閱讀一下源碼,看完博客閱讀源碼,一切so easy~。

下面的這個方法後面還要用到,dispatchTouchEvent方法中多次調用了這個方法。

\

再看第二點onInterceptTouchEvent方法:這個方法表示是否攔截事件。如果返回true,那麼事件會直接交給自身的onTouchEvent處理。為什麼會這樣呢?看下面的代碼塊:

\

第2104行,按下手機屏幕,走到這裡,2106行,這裡的disallowIntercept默認的情況下這裡得到的是false的(默認初始化出來的值計算),會走到2108行,調用onInterceptTouchEvent,如果我們復寫這個方法返回true,這是intercept的值就是true,再往下走會走到2238行,這時候mFirstTouchTarget是為null的,會走到2240。這裡又調用了dispatchTransformedTouchEvent方法,也就是本文中的第二個代碼塊,這時候第三個參數child是null,方法會走到2547或者2566行(具體是哪一個,whatever),然後調用了父類的dispatchTouchEvent方法,我們再去看父類的方法:

\

看到紅框框中的代碼了沒,直接調用了onTouchEvent。所以如果你的onInterceptTouchEvent返回true時會調用自身的onTouchEvent,事件就傳到自己的onTouchEvent了。

第三點,為啥事件不消費時會回傳給父view,我有點詞窮了。。。不知道該如何描述,原因就是遞歸。父View傳遞事件的時候是遞歸調用disPatchTouchEvent,當事件沒有被子View消費時,就會調用自己的onTouchEvent方法,所以從日志看起來的效果就是事件被回傳回去了。

關於自己對這方面的理解,總體上就這麼多,源碼的解析不太詳細,就大概理出來了個初步的條理,可能理解的存在問題甚至錯誤,歡迎指正。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved