天天看點

[Android] View和ViewGroup事件分發機制 1.涉及到事件響應的常用方法構成 2.android事件處理涉及到的三個重要函數 3.View源碼分析 4.ViewGroup源碼分析 5.總結

版權聲明:請尊重個人勞動成果,轉載注明出處,謝謝!

  使用者在手指與螢幕接觸過程中通過motionevent對象産生一系列事件,它有四種狀态: 

motionevent.action_down :手指按下螢幕的瞬間(一切事件的開始)

motionevent.action_move :手指在螢幕上移動

motionevent.action_up :手指離開螢幕瞬間

motionevent.action_cancel  :取消手勢,一般由程式産生,不會由使用者産生

  android中的事件onclick, onlongclick,onscroll, onfling等等,都是由許多個touch事件構成的(一個action_down, n個action_move,1個action_up)。

  android 事件響應機制是先 分發(先由外部的view接收,然後依次傳遞給其内層的最小view)再 處理 (從最小view單元(事件源)開始依次向外層傳遞。)的形式實作的。

  複雜性表現在:可以控制每層事件是否繼續傳遞(分發和攔截協同實作),以及事件的具體消費(事件分發也具有事件消費能力)。

事件分發:public boolean dispatchtouchevent(motionevent ev)

   當有監聽到事件時,首先由activity進行捕獲,進入事件分發處理流程。(因為activity沒有事件攔截,view和viewgroup有)會将事件傳遞給最外層view的dispatchtouchevent(motionevent ev)方法,該方法對事件進行分發。 

return true :表示該view内部消化掉了所有事件。

return false :事件在本層不再繼續進行分發,并交由上層控件的ontouchevent方法進行消費(如果本層控件已經是activity,那麼事件将被系統消費或處理)。 

如果事件分發傳回系統預設的 super.dispatchtouchevent(ev),事件将分發給本層的事件攔截onintercepttouchevent 方法進行處理

事件攔截:public boolean onintercepttouchevent(motionevent ev)

return true :表示将事件進行攔截,并将攔截到的事件交由本層控件 的 ontouchevent 進行處理;

return false :則表示不對事件進行攔截,事件得以成功分發到子view。并由子view的dispatchtouchevent進行處理。 

如果傳回super.onintercepttouchevent(ev),預設表示攔截該事件,并将事件傳遞給目前view的ontouchevent方法,和return true一樣。

事件響應:public boolean ontouchevent(motionevent ev)

  在dispatchtouchevent(事件分發)傳回super.dispatchtouchevent(ev)并且onintercepttouchevent(事件攔截傳回true或super.onintercepttouchevent(ev)的情況下,那麼事件會傳遞到ontouchevent方法,該方法對事件進行響應。

如果return true,表示ontouchevent處理完事件後消費了此次事件。此時事件終結;

如果return fasle,則表示不響應事件,那麼該事件将會不斷向上層view的ontouchevent方法傳遞,直到某個view的ontouchevent方法傳回true,如果到了最頂層view還是傳回false,那麼認為該事件不消耗,則在同一個事件系列中,目前view無法再次接收到事件,該事件會交由activity的ontouchevent進行處理;  

如果return super.dispatchtouchevent(ev),則表示不響應事件,結果與return false一樣。

從以上過程中可以看出,dispatchtouchevent無論傳回true還是false,事件都不再進行分發,隻有當其傳回super.dispatchtouchevent(ev),才表明其具有向下層分發的願望,但是是否能夠分發成功,則需要經過事件攔截onintercepttouchevent的稽核。事件是否向上傳遞處理是由ontouchevent的傳回值決定的。
[Android] View和ViewGroup事件分發機制 1.涉及到事件響應的常用方法構成 2.android事件處理涉及到的三個重要函數 3.View源碼分析 4.ViewGroup源碼分析 5.總結

(圖來自網絡)

  android中imageview、textview、button等繼承于view但沒有重寫的dispatchtouchevent方法,是以都用的view的該方法進行事件分發。 

看view重要函數部分源碼:

 首先進行三個條件的判斷:

(1)檢視是否給button設定了ontouchlistener()事件;

(2)控件是否enable;(控件預設都是enable的)

(3)button裡面實作的ontouchlistener監聽裡的ontouch()方法是否傳回true;

 如果條件都滿足,則該事件被消耗掉,不再進入ontouchevent中處理。否則将事件将交給ontouchevent方法處理。

隻有我們注冊ontouchlistener時重寫的  ontouch()方法中 傳回false —> 執行ontouchevent方法 —> 導緻onclick()回調方法執行  傳回true —> ontouchevent方法不執行 —> 導緻onclick()回調方法不會執行

  android中諸如linearlayout等的五大布局控件,都是繼承自viewgroup,而viewgroup本身是繼承自view,是以viewgroup的事件處理機制對這些控件都有效。

   

部分源碼:

1、dispatchtouchevent作用:決定事件是否由onintercepttouchevent來攔截處理。  傳回super.dispatchtouchevent時,由onintercepttouchevent來決定事件的流向  傳回false時,會繼續分發事件,自己内部隻處理了action_down  傳回true時,不會繼續分發事件,自己内部處理了所有事件(action_down,action_move,action_up) 2、onintercepttouchevent作用:攔截事件,用來決定事件是否傳向子view  傳回true時,攔截後交給自己的ontouchevent處理  傳回false時,攔截後交給子view來處理 3、ontouchevent作用:事件最終到達這個方法  傳回true時,内部處理所有的事件,換句話說,後續事件将繼續傳遞給該view的ontouchevent()處理  傳回false時,事件會向上傳遞,由ontoucevent來接受,如果最上面view中的ontouchevent也傳回false的話,那麼事件就會消失

如果viewgroup找到了能夠處理該事件的view,則直接交給子view處理,自己的ontouchevent不會被觸發; 

可以通過複寫onintercepttouchevent(ev)方法,攔截子view的事件(即return true),把事件交給自己處理,則會執行自己對應的ontouchevent方法。

子view可以通過調用getparent().requestdisallowintercepttouchevent(true); 阻止viewgroup對其move或者up事件進行攔截;  

一個點選事件産生後,它的傳遞過程如下: 

activity->window->view。頂級view接收到事件之後,就會按相應規則去分發事件。如果一個view的ontouchevent方法傳回false,那麼将會交給父容器的ontouchevent方法進行處理,逐級往上,如果所有的view都不處理該事件,則交由activity的ontouchevent進行處理。 

如果某一個view開始處理事件,如果他不消耗action_down事件(也就是ontouchevent傳回false),則同一事件序列比如接下來進行action_move,則不會再交給該view處理。

viewgroup預設不攔截任何事件。 

諸如textview、imageview這些不作為容器的view,一旦接受到事件,就調用ontouchevent方法,它們本身沒有onintercepttouchevent方法。正常情況下,它們都會消耗事件(傳回true),除非它們是不可點選的(clickable和longclickable都為false),那麼就會交由父容器的ontouchevent處理。 

點選事件分發過程如下 dispatchtouchevent—->ontouchlistener的ontouch方法—->ontouchevent–>onclicklistener的onclick方法。也就是說,我們平時調用的setonclicklistener,優先級是最低的,是以,ontouchevent或ontouchlistener的ontouch方法如果傳回true,則不響應onclick方法…

繼續閱讀