事件分發機制(一):解惑篇

前言

本文粗略解析下事件分發機制,後續會分析下源碼,但願可以幫助到你們解惑一二。函數

從一個例子提及cdn

在實踐中,大多數須要瞭解事件分發機制的可能就是滑動衝突了,須要瞭解何時到底誰應該處理這個事件,先來看個例子,當咱們點擊區域Viewblog

默認不處理事件

假如ViewGroup和View都默認不處理事件,不復寫對應函數事件

  • DOWN事件傳遞到View的onTouchEvent,返回false,表示View自己不關心此次事件
  • DOWN事件傳遞到ViewGroup的onTouchEvent,返回false,表示ViewGroup自己不關心此次事件
  • 最終事件回溯到Activity中,由最上層處理事件

因爲onTouchEvent中返回了false,同時也就表明着不關心本次事件(我不關心此次手勢,不要來找我了),後續的MOVE,UP事件也不會傳遞進來源碼

View處理事件

假設View是須要處理事件,好比是Button之類的View,默認是可點擊的it

  • DOWN事件傳遞到View的onTouchEvent,返回True,處理本身的邏輯
  • 由於View中的onTouchEvent返回了True,表示有人願意處理了這個事件,那麼後續事件將不會傳遞到ViewGroup以及上層的onTouchEvent中了,後續的事件將由View自己進行處理

注意上述的前提是ViewGroup不會對此事件進行攔截,由於在DOWN事件傳遞到View的ontouchEvent以前,ViewGroup是有一次攔截機會的,若是ViewGroup的onInterceptTouchEvent返回false,則不攔截,可是注意下一次的MOVE、UP等事件仍是會走ViewGroup攔截的判斷,可根據邏輯進行攔截處理,若是沒有攔截,可是View的ontouchEvent返回了false,也就表示下面沒有View是願意處理這個事件的,那麼這個燙手的山芋(事件)仍是會回到ViewGroup的ontouchEvent中io

同時可見DOWN事件的返回值,其實就是表示着View自己對本次事件處理的意願如何,True則表明着願意處理該事件,false則表明不關心本次事件class

ViewGroup攔截事件

假如ViewGroup在DOWN事件中,攔截了事件onInterceptTouchEvent返回了true,那麼此時事件直接轉到ViewGroup的ontouchEvent中,後續的MOVE、UP事件也會交給ViewGroup處理,View是沒有機會處理到事件的,即便此時調用requestDisallowInterceptTouchEvent也是無效的request

假如ViewGroup在DOWN事件中沒有攔截事件,可是在MOVE中卻對事件進行了攔截處理,好比相似如ScrollView同樣,是能夠對其中的View進行點擊處理的,可是在滑動時,ScrollView須要處理本身的邏輯,這時候就在MOVE中攔截了事件lazyload

  • DOWN事件傳遞在ViewGroup中,但此時並不想攔截,onInterceptTouchEvent返回false,事件傳遞到View的ontouchEvent中,消費掉返回True
  • MOVE事件傳遞到ViewGroup中,此時ViewGroup須要對事件進行攔截處理,onInterceptTouchEvent返回True,可是View還苦巴巴的等着事件呢,由於以前在ontouchEvent中返回了True,那麼此時這個MOVE事件將會被系統變成一個CANCEL事件,這個CANCEL事件將會傳遞給VIEW的onTouchEvent方法,告訴你,別等了,你的事件被取消了
  • 當MOVE事件或者UP事件再次進入ViewGroup的時候,注意此時因爲以前已經攔截了事件,這次事件並不會走onInterceptTouchEvent的判斷,能夠理解爲onInterceptTouchEvent一旦返回了True,那麼後續的一系列事件就默認已經被攔截處理了,不會再去判斷!而是會直接傳遞給ViewGroup的onTouchEvent方法去處理了
  • 此時View就不會受到任何的事件了

總結

  • 同一時間序列事件是指以down事件開始,中間含有數量不定的move事件,最終以up事件結束。

  • 各個View的onTouchEvent方法對DOWN事件的處理,表明了該View對以此DOWN開始的整個手勢事件的處理意願,True表明須要處理這次事件,false則表示不關心,事件會回傳到上層View的ontouchEvent中

  • 若是ViewGroup一旦決定攔截一個事件,也就是onInterceptTouchEvent返回True,那麼後續的同一時間序列事件將會被默認攔截,不會再調用onInterceptTouchEvent方法,後續事件會交給ontouchEvent進行處理

  • 事件一旦交給一個View處理,那麼它就必須消耗掉,不然同一事件序列中剩下的事件就再也不交給他來處理了,若是ontouchEvent中返回false,那麼後續事件不會再傳遞進來

  • 若是ViewGroup攔截了一個半路的事件(好比,MOVE),這個事件將會被系統變成一個CANCEL事件,並傳遞給以前處理該手勢(gesture)的子View,並且不會再傳遞(不管是被攔截的MOVE仍是系統生成的CANCEL)給ViewGroup的onTouchEvent方法。只有再到來的事件纔會傳遞到ViewGroup的onTouchEvent方法中。

請幫頂 / 評論點贊!由於你的鼓勵是我寫做的最大動力!

相關文章
相關標籤/搜索