想作架構師?你真的明白Android事件分發機制嗎?

嗨,你終於來啦 ~ 等你很久啦~ 從今天開始天天分享一篇Android須要瞭解的知識點,喜歡的小夥伴歡迎關注,我會按期分享Android知識點及解析,還會不斷更新的BATJ面試專題,歡迎你們前來探討交流,若有好的文章也歡迎投稿。更新了兩天Android基礎小知識,今天咱們來說講Android進階必需要了解的事件分發機制。面試

1、簡介

或許你會問,「爲何我必定要知道View的事件分發機制?」。由於咱們在實際開發的過程當中,常常會遇到多層的View互相嵌套之後,對某一個View進行滑動的時候,特別不靈敏,甚至於無法滑動。這種滑動衝突的解決須要咱們清楚的掌握View的事件分發機制。那下面咱們詳細的講解下View的整個事件機制。
Android將View的事件封裝到MotionEvent這個類中,這也是監聽touch事件中回調給咱們的參數 public boolean onTouchEvent(MotionEvent event) 。一般事件咱們主要關心下面幾種類型:spa

  • MotionEvent.ACTION_DOWN

當咱們手指按下屏幕的第一個事件即是ACTION_DOWN了,也就是意味着事件的開始。code

  • MotionEvent.ACTION_MOVE

當咱們手指按下屏幕後,在屏幕上滑動的過程,此事件就會不斷的觸發。orm

  • MotionEvent.ACTION_UP

此事件在咱們手指從屏幕擡起的時候會觸發。cdn

  • MotionEvent.ACTION_CANCEL

這個事件提及來稍微複雜一點,舉個栗子:當咱們的外層View將事件傳遞給內層View去處理時,外層View的攔截方法通常會返回false,可是當某個條件觸發後,外層View想本身處理接下來的事件,就攔截了事件分發,此時內層View就會收到ACTION_CANCEL的事件。blog

  • MotionEvent.ACTION_OUTSIDE

這個事件咱們不經常使用到,考慮這種場景。咱們又一個Diallog彈出,當咱們按Dialog之外的屏幕將Dialog消失掉。這個時候能夠考慮監聽這個事件,要想使用這個事件咱們必須對當前的 Window 設置一個Flag: FLAG_WATCH_OUTSIDE_TOUCH事件

下面咱們介紹和事件分發相關的幾個方法:開發

  • dispatchTouchEvent(MotionEvent event)

這個方法是用來處理向下分發事件邏輯的,咱們經過觀察ViewGrope源碼中的代碼知道,這個方法細節較多,檢出咱們比較關心的邏輯就是這個方法會先判斷子View是否有調用disallowIntercept父View去攔截事件,若是沒有,父View本身會調用onInterceptTouchEvent判斷本身是否有攔截,若是攔截事件,將調用父View本身的onTouchEvent方法去處理事件,若是沒有攔截事件,事件將繼續分發到子View中處理。源碼

  • onInterceptTouchEvent(MotionEvent event)

用來申明是否攔截事件繼續向下分發,若是返回true,事件將不會繼續向下分發,而是交由本身的onTouchEvent方法處理。it

  • onTouchEvent(MotionEvent event)

顯然,這個就是事件處理的方法了。

  • onTouch(MotionEvent event)

這個方法是在咱們對某一個 setOnTouchListener 時回調,也就是在傳遞事件的時候,在交給View自己的onTouchEvent處理以前判斷是否有監聽的TouchListener,若是有優先調用TouchListener的onTouch方法處理。

2、詳細分析View的分發事件

咱們都知道,Android的View是樹形結構的,因此當一個事件來臨的時候通常是從根部分發下來的。爲了方便咱們接下來的理解,咱們構建一個這樣的例子:

假設咱們有這樣一個頁面,最外層是一個ViewGroup A,裏面嵌套着一個ViewGroup B,B裏面有一個ViewGroup C。

情景1

假設咱們對事件不作任何攔截,也不作任何處理。當咱們點擊View C,這個時候咱們看到的Log顯示調用順序爲:

A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
C -> dispatchTouchEvent
C -> onInterceptTouchEvent
C -> onTouchEvent ACTION_DOWN
B -> onTouchEvent ACTION_DOWN
A -> onTouchEvent ACTION_DOWN
複製代碼

因爲沒有任何View處理事件,最終會回調到Activity的onTouchEvent中去處理。從這個情景中咱們能夠知道,事件向下傳遞的過程以及處理事件的向上傳遞的過程。

情景2

假設咱們在View B的onTouchEvent中返回true,再次點擊事件並滑動,咱們獲得的Log以下:

A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
C -> dispatchTouchEvent
C -> onInterceptTouchEvent
C -> onTouchEvent ACTION_DOWN
B -> onTouchEvent ACTION_DOWN

A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onTouchEvent ACTION_MOVE

A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onTouchEvent ACTION_UP 
複製代碼

咱們發現,除了ACTION_DOWN事件會下發到C,後續的事件不會再下發這是由於,當咱們發現某一層View的onTouchEvent返回true之後,會有一個標誌位表示後續的事件都由此View處理,後續事件再也不下發到子View,直到 ACTION UP 事件後將標誌位重置。

情景3* :

假設咱們在View B的onInterceptTouchEvent中返回true,再次點擊C會怎麼樣呢?咱們獲得以下的Log記錄:

A -> dispatchTouchEvent
A -> onInterceptTouchEvent
B -> dispatchTouchEvent
B -> onInterceptTouchEvent
B -> onTouchEvent ACTION_DOWN
A -> onTouchEvent ACTION_DOWN
複製代碼

相比較於情景2,ACTION_DOWN事件不會下發到C,因爲沒有View表示能處理,因此後續的事件均被取消。

3、總結

經過咱們實際運行和分析源碼發現,咱們ViewGroup事件的分發流程以下所示:

2.jpg

對着上圖你們不妨嘗試分析下:

  • 若是B的onInterceptTouchEvent中返回true而且onTouchEvent中返回true,那麼Log又將是怎樣的呢?

知道的小夥伴們能夠在下面評論回答哦~

相關文章
相關標籤/搜索