事件分發機制

2022-08-22 06:24:11 字數 3588 閱讀 6677

view的事件分發

對於事件分發機制,舉個簡單的例子,在乙個activity中只有乙個按鈕,如果我們想給這個按鈕註冊乙個點選事件,只需要呼叫setonclicklistener方法,這樣在onclick方法裡面寫實現的**,就可以在按鈕被點選的時候執行.我們再給這個按鈕新增乙個touch事件,只需要呼叫setontouchlistener方法,ontouch方法裡能做的事情比onclick要多一些,比如判斷手指按下、抬起、移動等事件。如果我兩個事件都註冊了,我之前做過乙個實驗,執行程式點選按鈕的結果是ontouch是優先於onclick執行的,並且ontouch執行了兩次,一次是action_down,一次是action_up(你還可能會有多次action_move的執行,如果你手抖了一下)。因此事件傳遞的順序是先經過ontouch,再傳遞到onclick。

ontouch方法是有返回值的,如果我們嘗試把ontouch方法裡的返回值改成true,再執行一次就會發現onclick方法不再執行了,這是因為ontouch方法返回true就認為這個事件被ontouch消費掉了,因而不會再繼續向下傳遞。

我看過事件分發的一些原始碼,

只要你觸控到了任何乙個控制項,就一定會呼叫該控制項的dispatchtouchevent方法。那當我們去點選按鈕的時候,就會去呼叫button類裡的dispatchtouchevent方法,可是你會發現button類裡並沒有這個方法,那麼就到它的父類textview裡去找一找,你會發現textview裡也沒有這個方法,那沒辦法了,只好繼續在textview的父類view裡找一找,這個時候你終於在view裡找到了這個方法,示意圖如下:

對於view中的dispatchtouchevent方法,在這個方法內,首先是進行了乙個判斷,裡面有三個條件,如果這三個條件都滿足,就返回true,否則就返回ontouchevent方法執行的結果。對於第乙個條件是乙個montouchlistener變數,這個變數是在view中的setontouchlistener方法裡賦值的,也就是說只要我們給控制項註冊了touch事件,montouchlistener就一定被賦值了。第二個條件是判斷當前點選的控制項是否是enable的,按鈕預設都是enable的,因此這個條件恆定為true。第三個條件最為關鍵,montouchlistener.ontouch(this, event),其實也就是去**控制項註冊touch事件時的ontouch方法。也就是說如果我們在ontouch方法裡返回true,就會讓這三個條件全部成立,從而整個方法直接返回true。如果我們在ontouch方法裡返回false,就會再去執行ontouchevent(event)方法。

結合我之前講的例子,首先在dispatchtouchevent中最先執行的就是ontouch方法,因此ontouch肯定是要優先於onclick執行的, 而如果在ontouch方法裡返回了true,就會讓dispatchtouchevent方法直接返回true,不會再繼續往下執行。而我做的實驗的結果也證實了如果ontouch返回true,onclick就不會再執行了。

這裡還講到了ontouchevent方法,這個方法要稍微複雜一點,如果我們的控制項是可以點選的,就會進入到switch判斷中去,而如果當前的事件是抬起手指,則會進入到motionevent.action_up這個case當中。在經過種種判斷之後,會執行到performclick()方法。

對於performclick()方法,只要monclicklistener不是null,就會去呼叫它的onclick方法。

而剛剛說過,當我們通過呼叫setonclicklistener方法來給控制項註冊乙個點選事件時,就會給monclicklistener賦值。然後每當控制項被點選時,都會在performclick()方法裡**被點選控制項的onclick方法。

這樣view的整個事件分發的流程就讓我們搞清楚了!

後來我還對touch事件的層級傳遞分析了一下,我們都知道如果給乙個控制項註冊了touch事件,每次點選它的時候都會觸發一系列的action_down,action_move,action_up等事件。這裡需要注意,如果你在執行action_down的時候返回了false,後面一系列其它的action就不會再得到執行了。簡單的說,就是當dispatchtouchevent在進行事件分發的時候,只有前乙個action返回true,才會觸發後乙個action。

如果我們換乙個控制項,將按鈕替換成imageview,然後給它也註冊乙個touch事件,並返回false 。我們會發現,

在action_down執行完後,後面的一系列action都不會得到執行了,因為imageview和按鈕不同,它是預設不可點選的,因此在ontouchevent裡判斷時無法進入到它內部一些語句,而是直接返回了false,也就導致後面其它的action都無法執行了。

touch事件分發的三個問題:

1. ontouchontouchevent有什麼區別,又該如何使用?

從原始碼中可以看出,這兩個方法都是在view的dispatchtouchevent中呼叫的,ontouch優先於ontouchevent執行。如果在ontouch方法中通過返回true將事件消費掉,ontouchevent將不會再執行。

另外需要注意的是,ontouch能夠得到執行需要兩個前提條件,第一montouchlistener的值不能為空,第二當前點選的控制項必須是enable的。因此如果我們有乙個控制項是非enable的,那麼給它註冊ontouch事件將永遠得不到執行。對於這一類控制項,如果我們想要監聽它的touch事件,就必須通過在該控制項中重寫ontouchevent方法來實現。

2.為什麼給listview引入了乙個滑動選單的功能,listview就不能滾動了?

如果你閱讀了android滑動框架完全解析,教你如何一分鐘實現滑動選單特效

滑動選單的功能是通過給listview註冊了乙個touch事件來實現的。如果我們在ontouch方法裡處理完了滑動邏輯後返回true,那麼listview本身的滾動事件就被遮蔽了,自然也就無法滑動(原理同前面例子中按鈕不能點選),因此解決辦法就是在ontouch方法裡返回false。

3.為什麼輪播器裡的使用button而不用imageview

提這個問題的朋友可看看android實現滾動控制項,含頁籤功能,讓你的應用像**一樣炫起來

這篇文章。這篇文章裡,在輪播器裡使用button,主要就是因為button是可點選的,而imageview是不可點選的。如果想要使用imageview,可以有兩種改法。第一,在imageview的ontouch方法裡返回true,這樣可以保證action_down之後的其它action都能得到執行,才能實現滾動的效果。第二,在布局檔案裡面給imageview增加乙個android:clickable="true"的屬性,這樣imageview變成可點選的之後,即使在ontouch裡返回了false,action_down之後的其它action也是可以得到執行的。

事件分發機制

android中的事件型別分為按鍵事件和螢幕觸控事件,touch事件是螢幕觸控事件的基礎事件,有必要對它進行深入的了解。乙個最簡單的螢幕觸控動作觸發了一系列touch事件 action down action move action move action move.action move acti...

事件分發機制

對於安卓事件傳遞和消費機制,他給我們提供了3個方法,dispatchtouchevent onintercepttouchevent 和ontouchevent 當監聽到事件時,首先由activity捕獲 開始進入事件分發流程.dispatchtouchevent 如果返回的是true,表明事件不會...

事件分發機制

1 public boolean dispatchtouchevent motionevent ev 事件分發方法,分發event所呼叫 2 public boolean onintercepttouchevent motionevent ev 事件攔截方法,攔截event所呼叫 3 public ...