轉:Android view事件傳遞機制

來源:互聯網
上載者:User
 

    針對由於觸摸(Touch)而觸發的事件。 Android的事件:onClick, onScroll, onFling等等,都是由許多個Touch組成的。其中Touch的第一個狀態肯定是ACTION_DOWN, 表示按下了螢幕。之後,touch將會有後續事件,可能是: ACTION_MOVE //表示為移動手勢 ACTION_UP

 

 

針對由於觸摸(Touch)而觸發的事件。

Android的事件:onClick, onScroll, onFling等等,都是由許多個Touch組成的。其中Touch的第一個狀態肯定是        ACTION_DOWN, 表示按下了螢幕。之後,touch將會有後續事件,可能是:

ACTION_MOVE //表示為移動手勢

ACTION_UP //表示為離開螢幕

ACTION_CANCEL //表示取消手勢,不會由使用者產生,而是由程式產生的

一個Action_DOWN, n個ACTION_MOVE, 1個ACTION_UP,就構成了Android中眾多的事件。
在Android中,有一類控制項是中還可以包含其他的子控制項,這類控制項是繼承於ViewGroup類,例如:ListView, Gallery, GridView。

還有一類控制項是不能再包含子控制項,例如:TextView。

本文的主要討論對象就是ViewGroup類的控制項嵌套時事件觸發情況。

對於ViewGroup類的控制項,有一個很重要的方法,就是onInterceptTouchEvent(),用於處理事件並改變事件的傳遞方向,它的傳回值是一個布爾值,決定了Touch事件是否要向它包含的子View繼續傳遞,這個方法是從父View向子View傳遞。

而方法onTouchEvent(),用於接收事件並處理,它的傳回值也是一個布爾值,決定了事件及後續事件是否繼續向上傳遞,這個方法是從子View向父View傳遞。

Touch事件在 onInterceptTouchEvent()和onTouchEvent以及各個childView間的傳遞機制完全取決於onInterceptTouchEvent()和onTouchEvent()的傳回值。傳回值為true表示事件被正確接收和處理了,傳回值為false表示事件沒有被處理,將繼續傳遞下去(只是傳遞方向不一樣,onInterceptTouchEvent()向子View傳,而onTouchEvent()向父View傳)。

具體情況如下:

ACTION_DOWN事件會傳到某個ViewGroup類的onInterceptTouchEvent,如果返回false,則DOWN事件繼續向子ViewGroup類的onInterceptTouchEvent傳遞,如果子View不是ViewGroup類的控制項,則傳遞給子View的onTouchEvent。

如果onInterceptTouchEvent返回了true,則DOWN事件傳遞給VIewGroup的onTouchEvent,不再繼續傳遞,並且之後的後續事件也都傳遞給它的onTouchEvent。

如果某View的onTouchEvent返回了false,則DOWN事件繼續向其父ViewGroup類的onTouchEvent傳遞;如果返回了true,則後續事件會直接傳遞給其onTouchEvent繼續處理。(後續事件只會傳遞給對於必要事件ACTION_DOWN返回了true的onTouchEvent)

/////`````````````````````````````````````````````````````````````````

 

以前寫 android ,對事件的處理沒有太深入,只是簡單的 onTouchEvent 就 ok 了,現在寫的 UI ,很多自訂群組件,父 view 和子view 都需要接收事件,然後處理。如果不弄明白它的事件傳遞機制,很難擁有好的使用者體驗。

Touchevent 中,傳回值是 true ,則說明消耗掉了這個事件,傳回值是 false ,則沒有消耗掉,會繼續傳遞下去,這個是最基本的。

在 View 中跟 Touch 相關的事件有 dispatchTouchEvent , interceptTouchEvnet , onTouchEvent 三種。 dispatchTouchEvent是負責分發事件的,事件從 activity 傳遞出來之後,最先到達的就是最頂層 view 的 dispatchTouchEvent ,然後它進行分發,如果返回false ,則交給這個 view 的 interceptTouchEvent 方法來決定是否要攔截這個事件,如果 interceptTouchEvent 返回 true ,也就是攔截掉了,則交給它的 onTouchEvent 來處理,如果 interceptTouchEvent 返回 false ,那麼就傳遞給子 view ,由子 view 的dispatchTouchEvent 再來開始這個事件的分發。

如果事件傳遞到某一層的子 view 的 onTouchEvent 上了,這個方法返回了 false ,那麼這個事件會從這個 view 往上傳遞,都是onTouchEvent 來接收。而如果傳遞到最上面的 onTouchEvent 也返回 false 的話,這個事件就會“消失”,而且接收不到下一次事件。(我說的一次事件指的是 down 到 up 之間的一系列事件)

我畫了個圖,見附件。

總結一下,如果這一次事件沒有人消耗掉,則系統不會給你下一次事件,因為他會認為你這次的事件阻塞了,沒必要給下一次。onTouchEvent如果不消耗的話,會從子view傳遞到父view。

 

 

又一個例子:

 

需求:要做一個完全通過flip手勢來切換的介面。在最上層用一個ViewFlipper作為容器,並檢測flip手勢操作。

難題:ViewFlipper的flip手勢檢測需要的MotionEvent會被各種子View的觸摸檢測給攔截了。比如介面上有一個Button,則當手指按下Button(還沒有抬起)然後flip出Button,則最上層的flip手勢檢測無效。

原因:android對Touch Event的分發邏輯是View從上層分發到下層(dispatchTouchEvent函數),然後下層優先開始處理Event(先mOnTouchListener,再onTouchEvent)並向上返回處理情況(boolean值),若返回true,則上層不再處理。

    於是我們首先想到,要保證flip手勢檢測,需要把所有的Touch Event都傳到上層去。

    然而在分發邏輯之外還有一個邏輯,android估計是為了保證每個觸操作只能由一個View來進行完整響應,對ACTION_DOWN事件有個額外的邏輯:如果某個View在處理ACTION_DOWN事件時返回false(即該View未處理此事件),那麼後續產生的其它事件將直接忽略掉這個View(不過LongPress又有另外的獨立邏輯)。舉例來說就是,如果你處理ACTION_DOWN時返回了false,那麼你這個View將得不到ACTION_MOVE或ACTION_DOWN等等這些後續事件了。

     於是難題出現了,你若把Touch Event都想辦法給傳到上層了(只能通過返回false來傳到上層),那麼下層的各種子View就不能處理後續事件了。

解決方案:

     開始僅著眼於Touch Event處理完後的回傳過程,想了N久不得,畢竟我想實現的是一個需要打破android事件處理邏輯的效果(就是一個連續性操作,只有不滿足上層要求時,才輪到下層處理)。然後突然想到事件的分發過程,便豁然開朗:

     覆寫最上層的View的dispatchTouchEvent函數,代碼如下:

      @Override
      public boolean dispatchTouchEvent(MotionEvent event) {

             if (_flipDetector.onTouchEvent(event)) {
             event.setAction(MotionEvent.ACTION_CANCEL);
             }

             return super.dispatchTouchEvent(event);
      }

      於是效果實現。也就是在分發之前便進行手勢檢測處理,若檢測成功,則取消下層的一切處理過程。

 

 

 

總結一下就是:onInterceptTouchEvent可以接受到所有的Touch事件,而onTouchEvent則不一定。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.