編輯:關於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方法,所以從日志看起來的效果就是事件被回傳回去了。
關於自己對這方面的理解,總體上就這麼多,源碼的解析不太詳細,就大概理出來了個初步的條理,可能理解的存在問題甚至錯誤,歡迎指正。
Android中Activity的四大啟動模式實驗簡述,androidactivity作為Android四大組件之一,Activity可以說是最基本也是最常見的組件,它提
硅谷新聞5--頂部新聞輪播圖事件處理,硅谷5--重寫dispatchTouchEvent,並且要在按下的時候 getParent().requestDisallowInt
android https正確調用方案(防中間人劫持),androidhttps以下內容為原創,歡迎轉載,轉載請注明 來自博客園:http://www.cnblogs.c
[android] 手機衛士黑名單功能(列表展示),android衛士先把要攔截的電話號碼保存到數據庫中,攔截模式用個字段區分,1 電話攔截,2 短信攔截,3全部攔截 &