Android On Touch 事件分析

  <a href="http://www.eoe%3Ca%20href%3D/" http:="" www.eoeandroid.com="" "="" target="_blank" class="relatedlink" style="word-wrap: break-word; color: rgb(51, 102, 153); border-bottom-width: 1px; border-bottom-style: solid; border-bottom-color: blue;">android.com/" target="_blank" class="relatedlink">Android的觸摸事件消息傳遞機制,網上的各種分析、總結很多,有深入源碼的,有圖文並茂的。你總結他總結,終歸也都是別人的總結,不是我總結。每次匆匆看過,知道個大概,也沒仔細琢磨過,總是過一陣就記不清細節了,但這回項目中遇到了相關問題,看來是要下功夫認認真真深入研究了。

       先奉獻上幾個不錯的資料,真是隨手一百度,金銀財寶擋不住:
                      http://blog.csdn.net/guitk/article/details/7057155      流程圖不錯;
                      http://blog.csdn.net/stonecao/article/details/6759189     源碼分析,可深入瞭解內部機制與函數調用過程;
                      http://www.cnblogs.com/xiaoQLu/archive/2013/04/02/2994030.html   這個也不錯;

       下面是用自己的話和畫來總結的:
       總共涉及到的知識包括:
  • dispatchTouchEvent
  • onInterceptTouchEven
  • onTouchEvent
       這三個函數與ViewGroup、View之間的消息傳遞(雖然ViewGroup繼承於View,但這裏爲了方便,ViewGroup是佈局容器,View是佈局內的控件)。
      以及ACTION_DOWN、ACTION_UP、ACTION_MOVE、ACTION_CANCEL這四種消息類型。


      觸摸事件是一連串ACTION_DOWN,ACTION_MOVE..MOVE…MOVE、最後ACTION_UP。

      從頭說起,先看ACTION_DOWN的處理。

      觸摸事件總是先由最下面的ViewGroup先收到,在dispatchTouchEvent 函數中向其子控件派發ACTION_DOWN消息,子控件可能是ViewGroup也可能是View。

       在派發給子控件之前要先調用ViewGroup的onInterceptTouchEvent攔截器,如果消息沒有被攔截,則向其子控件派發ACTION_DOWN消息(至於向哪個子控件派發消息,在dispatchTouchEvent 源碼中有命中測試)。如果子控件是ViewGroup,則由它的dispatchTouchEvent 函數再次進行消息派發,重複上面的工作(檢查攔截器,命中測試,向命中的子控件派發消息);如果子控件是View,則會由View的onTouchEvent響應ACTION_DOWN事件。

       如果在ViewGroup的onInterceptTouchEvent攔截器中將消息攔截了,則後續不會再向子控件傳遞ACTION_DOWN消息了,會直接將消息傳遞給這個ViewGroup的onTouchEvent進行響應。

       在控件進行onTouchEvent處理過程中,如果控件沒有消費這個ACTION_DOWN事件(即返回false,消費這個詞翻譯過來真彆扭,還是consume感覺順一點…),則會將ACTION_DOWN傳遞給其父ViewGroup的onTouchEvent進行處理,直到由哪一層ViewGroup消費了ACTION_DOWN事件爲止。

        如果有哪一個控件的onTouchEvent消費了ACTION_DOWN事件,則後續的n個ACTION_MOVE與1個ACTION_UP都會逐層傳遞到這個控件的onTouchEvent進行處理。

        這裏要注意是逐層,也就是說每層的攔截器還是可以攔截到後續的ACTION_MOVE與ACTION_UP。如果後續的ACTION_MOVE與ACTION_UP被某層的攔截器攔截,則後續的事件將不會再傳遞給之前處理onTouchEvent的子控件,而是逐層傳遞給由攔截消息的這個控件的onTouchEvent函數進行處理,並且會向其之前接收事件的子控件發送一個ACTION_CANCEL,表示後續事件被取消了。

        如果所有控件的onTouchEvent都沒有消費ACTION_DOWN事件,每層dispatchTouchEvent 都會返回false,表示事件沒有被派發出去,後續的ACTION_MOVE與ACTION_UP也都不會再被傳遞了。

        這個就是整個觸摸事件消息傳遞的流程。

       還有一種極端的情況,如果某個控件一開始消費了ACTION_DOWN,可是ACTION_MOVE接連來找它消費的時候,它並不消費ACTION_MOVE,但是後續的ACTION_MOVE與UP還是會來找它(真是嫁雞隨雞嫁狗隨狗…),只是每層的dispatchTouchEvent 會返回false,說明事件沒被消費。此時如果想讓上層ViewGroup接管事件,則必須由該ViewGroup在onInterceptTouchEvent中進行攔截。

       (ViewGroup真是富二代,層次高地位高,巧取豪奪?!攔截後,它只會給我等下層階級屌絲一個ACTION_CANCEL說被取消了…還不如叫ACTION_CANCEL_SO_SORRY_TO_YOU_DIAOSI!!!哈哈,整篇文章都儘量措辭嚴謹但還是在最後失了節操)。


        後記:話說之前做過MFC/WinForm,也小玩過WPF,其消息傳遞機制在這些框架中都大同小異。雖然本人身在研究院所,但真不清閒,項目太多太急了,有時因爲項目進度緊張,連續加班到深夜,許多知識點沒時間細細消化,GOOGLE、微軟大師們精雕細琢的迷人的經典的應用框架也沒細細品味,真是遺憾!好想有個8/2工作,80%的時間在公司正常項目上,20%甚至更多的時間能用來學習充電和整點cool的東西!!
圖1.ACTION_DOWN都沒被消費

圖2-1.ACTION_DOWN被View消費了


圖2-2.後續ACTION_MOVE和UP在不被攔截的情況下都會去找VIEW
圖3.後續的被攔截了


 

5.jpg (37.13 KB, 下載次數: 2)

下載附件  保存到相冊

圖4 ACTION_DOWN一開始就被攔截

2013-12-26 21:11 上傳



圖4ACTION_DOWN一開始就被攔截

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