淺析Android觸摸事件分發原理

    下面將以概念結合實例的方式,來講解android中觸摸事件的分發機制。

一,觸摸事件傳遞的基本流程(默認情況)

通常,一個應用的一個頁面是由Activity及view組成的,而view(通常是一個view樹)則是由一系列layout對象和view對象組成的。一個事件傳遞的基本流程如下:


圖1

     從圖中可以看出,事件總是先從Activity中的dispatchTouchEvent傳遞到view樹中,自頂向下,依次傳遞到onInterceptTouchEvent(該方法表明此viewgroup是否攔截時間,默認情況下不攔截,所以繼續向下傳遞),最後傳遞到葉節點——即view對象,於是執行該對象的onTouchEvent方法(該方法決定是否消費此事件,默認情況下,事件不消費,於是事件自底向上傳遞,如果沒有view對象來處理此事件,則最後會一直傳遞到Activity中來)。

    但在我們的應用開發中,肯定是希望對事件進行處理的,不然View就只是個擺設,而不能與用戶交互了。舉一個最簡單的例子,我們在使用android中自帶的Button的時候,Button默認是能消費該事件的,這是因爲Button類中重寫了onTouchEvent方法,在Button可點擊的情況下,該方法的返回值是true。這裏引申出了一個問題,即我們在想要使某個view對象能處理某個事件,是如何去做的呢?——即靠什麼方式來改變上圖中觸摸事件默認傳遞的流程的呢?

    答案是:通過集成ViewGroup/View來重寫onInterceptTouchEvent或onTouchEvent, 並改變它的返回值(true or false)。Android 框架真是通過去判斷具體的view對象的這些方法的返回值來決定事件的走向的。


二, 觸摸事件傳遞的改變(自定義情況)

   下面來以Button對象消費點擊事件爲例,給出事件傳遞的流程圖,如下圖所示。


圖2

    可以看到,事件默認傳遞到Button中時,Button處理了此事件(通過重寫onTouchEvent並返回true),所以事件就不會像圖1那樣自底向上的傳遞回去,因爲它已經被處理了(一次事件只會被處理一次)。

    與重寫View對象從而使得具體的View能處理事件類似,我們也通常會通過重寫ViewGroup對象的方法來使得事件能按想要的方式傳遞,比如,一個ListView要處理滑動事件,那麼它必須要攔截上下滑動事件(ListView通常是上下滑動的)並由自己來處理。那麼是怎麼做到的呢?事件如何攔截呢?攔截後又是如何處理它呢?

    答案是:通過重寫ViewGroup類的onInterceptTouchEvent,並判斷是上下滑動的情況下,攔截事件(將返回值置爲true);攔截之後事件就會交給onTouchEvent來處理,所以應該重寫onTouchEvent並將返回值也置爲true,然後進行滑動處理。下圖給出了更改後事件的傳遞流程。


圖3

    從圖中可以看到,ListView在攔截事件後就不會傳遞到它的子節點Button了。(但這不意味着Button永遠不能接受到事件了,在一次事件完成後——即ACTION_UP之後,下一次的事件又會根據程序的處理來走一次新的流程。如,下一次執行Button上的點擊,這個時候由於它不滿足上下滑動,所以ListView是不會攔截此事件的,於是Button就能正常的接收到此事件了)。


三,結論

    從以上幾種實例,可以得出結論:

    1. 事件的攔截是自頂向下——某節點攔截了事件後,就不會繼續往下傳遞;

    2. 事件的消費優先級是自底向上——最低端的節點最先決定時候消費該事件,如果是,則事件不會被其父節點處理。

    3. 只有ViewGroup對象才能攔截事件,且一個事件被攔截後,將交由它的onTouchEvent方法來處理。


四,ViewPager+ListView實例

通過上述的實例講解及結論,我們來以實現ViewPager+ListView的組合View(這裏的情況是,ViewPager包含了ListView,並默認ViewPager是橫向滑動的,ListView是縱向滑動的,在用戶橫着滑動時,事件交由ViewPager來處理,縱向滑動時,事件交由ListView來處理)

   這裏仍然以圖示的方法來給出事件傳遞的流程。


圖4

   該圖只是給處理基本的流程,具體的處理細節依據我們想要達到的效果而定,但基本的思路不變。有了以上的知識,就可以完成更復雜的自定義View事件處理機制。


五, 最後

   該博文只是作爲對觸摸事件分發的淺析,當然有很多細節沒有說到,如果想對其有更深入、更細緻的瞭解,可以通過自己寫Demo測試並結合Android源碼的閱讀來達到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章