天天看點

Android觸摸事件(筆記篇)

類似标題的文章在網上不要講的太多,我也曾經以為自己掌握了,直到最近用的時候發現問題,才知道自己之前并非真的了解了,遂寫下這篇筆記、

事件分發傳遞的邏輯取決于action_down

同時要注意的是action_move和action_up的流程并不完全跟action_down一樣

下面這幅圖是action_down手勢的處理邏輯圖

Android觸摸事件(筆記篇)

以前我對手勢處理的概念也僅僅停留在這裡,而且我還錯誤的把action_move和action_up的邏輯也理所應當的想成這樣(就我身邊的情況來看,并不僅僅是我這麼認為)。

這裡我們以viewgroup為例來總結一下(注意,為了友善了解,我隻分析了viewgroup,activity和view有些許不同)

dispatchtouchevent

可以消費事件

如果傳回true,則自己消費掉事件,終止傳遞;

如果傳回false,不消費事件,交由父的ontouchevent做處理;

如果傳回super,不消費事件,将事件派發給onintercepttouchevent做處理。

onintercepttouchevent

不能消費事件

如果傳回true,将事件派發給自己的ontouchevent做處理;

如果傳回false/super,将事件派發給子的dispatchtouchevent做處理;

ontouchevent

如果傳回false/super,将事件派發給父的ontouchevent做處理;

大家可以看到,最終消費掉事件的位置隻有兩個,dispatchtouchevent和ontouchevent傳回true的時候,而且在它們傳回為false的時候,都是将事件交給上層的ontouchevent來處理,它們一個在onintercepttouchevent前,一個在onintercepttouchevent後,而onintercepttouchevent隻是将事件進行分流,這樣就構成了這張android事件傳遞圖、

關于action_move和action_up

總結一句話,在預設都傳回super的情況下,哪一層的ontouchevent傳回true,那一層的ontouchevent才會收到action_move和action_up,跟它同級及以上的dispatchtouchevent和onintercepttouchevent能收到action_move和action_up,如下圖所示

Android觸摸事件(筆記篇)

從上圖中我們可以看到,最終能夠收到action_move和action_up的ontouchevent隻能有一個,就算你上層的onintercepttouchevent對action_move傳回了true,那也隻會把action_move事件分發到上一層,子view就不會收到action_move事件了,也就是說,當一個view在ontouchevent裡的action_down裡面傳回了true,那它的action_move和action_up事件不管傳回什麼結果其實都是一樣的,因為action_move事件已經分發到這了,就算傳回false上層也是收!不!到!的!(這個概念跟我以前的三觀是完全不符的,當然你覺得錯誤也可以反駁我,剛開始我自己都不太相信)

requestdisallowintercepttouchevent的使用

在手勢進行中,我們還可以使用requestdisallowintercepttouchevent方法,來駁回onintercepttouchevent對事件的攔截

對于某些groupview,它會在onintercepttouchevent事件中攔截action_move事件,例如listview、scrollview等,這個時候childview就無法擷取到action_move事件了(常見的scrollview嵌套viewpager,viewpager無法滑動),除了重寫groupview的onintercepttouchevent方法,我們還可以重寫childview的dispatchtouchevent方法來解決、

首先,不管再霸道的groupview,在預設情況下,都不會在onintercepttouchevent的action_down事件傳回true的,因為這樣會導緻childview根本沒有擷取手勢的機會。那麼,childview在dispatchtouchevent方法中就能收到action_down事件,這個時候,我們調用parent的requestdisallowintercepttouchevent方法,設定為true,來通知groupview不要攔截我的事件,那麼接下來,原本應該被groupview攔截的action_move事件就會繞過groupview的onintercepttouchevent方法,直接下傳到childview的dispatchtouchevent

Android觸摸事件(筆記篇)

而值得注意的是,在dispatchtouchevent中getparent().requestdisallowintercepttouchevent(false)和return false效果是不同的

當groupview.requestdisallowintercepttouchevent(true)時,ontouchevent方法并不會接收到任何事件,是以此時若在childview的dispatchtouchevent方法中return false,其實效果是跟return true一樣的。隻有當groupview.requestdisallowintercepttouchevent(false)時,手勢才會再次交給groupview處理。

是以,這時,在childview中假如你想隻消費某一類型的action_move事件(如水準滑動),那就需要調用getparent().requestdisallowintercepttouchevent(false),而不是return false,如下圖所示:

Android觸摸事件(筆記篇)

另外,網上很多在action_up的時候會調用getparent().requestdisallowintercepttouchevent(false),其實并不是必要的,因為在收到action_down時,groupview預設會重新将requestdisallowintercepttouchevent設定為false狀态。

作者:卌梓

來源:51cto

繼續閱讀