最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

Android 事件分發(fā)流程淺析

2022-02-18 23:13 作者:房頂上的鋁皮水塔  | 我要投稿

事件分發(fā)流程模型

假設(shè)當(dāng)前Activity中存在兩個ViewGroup,每一個ViewGroup中各自有3個View。大致的模型是一個這樣的結(jié)構(gòu):

事件分發(fā)流程的四個特點

事件的分發(fā)流程是通過【傳播鏈】進行的,最頂層是Activity,最下層是View

  1. 事件傳播鏈不能跨級別,只能逐級別發(fā)送

  2. 傳播鏈形成之后,會按照之前的傳播鏈直接進行(傳播鏈具有記憶性)

  3. 傳播鏈行程后,View可以通過api影響傳播鏈

  4. 相對上層的View具有兩次對于事件的處理機會

    1. 剛收到事件

    2. 沒有子View處理事件

事件的種類

ACTION_DOWN

ACTION_MOVE

ACTION_UP

ACTION_CANCEL

前言:View的事件處理邏輯

ViewGroup也是一個View,在這個事件分發(fā)的過程中,不免會調(diào)用到View的dispatchTouchEvent方法, 我們首先分析一下這個。

View#dispatchedTouchEvent

這塊的邏輯比較單純,總結(jié)來說,如果是設(shè)置了touchListener的話,就回執(zhí)行onTouch回調(diào);否則就回看看onTouchEvent咋寫的。

View#setOnTouchListener中的lambda的返回值會影響onClick

設(shè)置的setOnTouchListener的結(jié)果會影響onClick的執(zhí)行。我們同時也分析一下這個過程。

在上面的代碼中,如果沒有設(shè)置onTouchEvent,result默認(rèn)為false,所以會執(zhí)行onTouchEvent,在onTouchEvent中,當(dāng)motionEvent為action_up時,會調(diào)用performClickInternal():

在performClick中才會調(diào)用onClick。所以onClick的執(zhí)行在onTouch之后,同時受到OnTouchListener的返回值的影響。在OnClickListener中手動調(diào)用performClick可以緩解這個問題。

事件分發(fā)流程的代碼解析

事件分發(fā)流程的執(zhí)行過程是從Activity開始的,到View結(jié)束,具體的傳播鏈(調(diào)用鏈)如下:

Activity在收到事件之后,其實會交給PhoneWindow處理。

PhoneWindow中持有DecorView,然后會調(diào)用DecorView的相關(guān)方法:

DecorView其實是一個FrameLayout,因此現(xiàn)在調(diào)用的重點就進入了ViewGroup#dispatchTouchEvent。

ViewGroup#dispatchTouchEvent?

ACTION_DOWN事件來臨

滑動觸摸的起始一般是從down事件開始,緊接著是一連串的move事件,最后以up事件結(jié)束。事件的傳遞機制非常的復(fù)雜,其中的細節(jié)點非常多,我通過圖示的方式也很難很好地呈現(xiàn),所以我想將這個ViewGroup#dispatchTouchEvent拆分成很多小塊,揉碎了來講解,在最后再進行回顧。

首先我們先看看當(dāng)ACTION_DOWN到來時的代碼邏輯:

Case#1 action_down & onInterceptTouchEvent 返回true

假設(shè)此時在ViewGroup2中重寫了onInterceptTouchEvent返回true的邏輯,我們看下面的代碼,代碼高度簡化后就是這樣的邏輯:

在這個情況下,會調(diào)用dispatchTransformedTouchEvent,其中child!=null的情況,我們緊接著具體看看:

super指的就是View#dispatchTouchEvent,上面已經(jīng)分析過。

Case#1 action_down & onInterceptTouchEvent 返回false

如果是返回false的話,就需要執(zhí)行if語句。在這個if語句中,會構(gòu)建當(dāng)前ViewGroup的View的優(yōu)先級,具體是通過z坐標(biāo)來排序的。這個過程通過buildTouchDispatchChildList()實現(xiàn)。

for循環(huán)中,主要的邏輯是這樣:

首先通過調(diào)用dispatchTransformedTouchEvent進行分發(fā), 如果返回true,就進行一些變量的設(shè)置。

這個地方,我個人認(rèn)為是事件分發(fā)的機制的精髓所在。因為dispatchTransformedTouchEvent讓child!=null時,會調(diào)用子View的dispatchTouchEvent,在我們的例子中,當(dāng)前的ViewGroup2的下面全部都是子View,但是在更復(fù)雜的情況下,ViewGroup2中會有嵌套更加深層的ViewGroup。通過這樣的分析,我們可以簡單把這里理解為【遞歸】的開始。

回到我們這個簡單的例子,如果ViewGroup2傳到View1,View1選擇消費事件,View#dispatchTouchEvent返回true,這里就進入if條件(不過如果有更深層的View嵌套,具體的分析也大差不差)


會設(shè)置:

并且中斷當(dāng)前的for循環(huán)。此時在后續(xù)的條件判斷中,會走if的第二個分支,設(shè)置handled為true并且返回給Activity,這樣就達成了一次從Activity-> ViewGroup -> View的事件傳遞。

Case#3?action_move

在后續(xù)的事件中,同樣會從Activity開始分發(fā),然后走到ViewGroup這里。

因為不是滑動事件的開始(action_down),因此不會重新構(gòu)建View的列表。

而且在第一次的過程中,有些重要的變量,如mFirstTouchTarget已經(jīng)被賦值了,所以邏輯會稍微有些改變,在后續(xù)的流程中會繼續(xù)dispatchTransformedTouchEvent,這樣其實又是一個【遞歸】的過程。

同時需要注意一點的是,在子View中可以通過getParent().reqeustDisallowInterceptTouchEvent進行事件攔截,這樣就不會調(diào)用父ViewGroup的onInterceptTouchEvent。

實踐例子

我直接使用老師上課的那個例子說明一下問題。在老師的例子中,只用了一個ViewPager作為ViewGroup,其中包含了一個ListView。繼承自ViewPager的ViewGroup中重寫了onInterceptTouchEvent,返回true。

改動1

此時,對于down事件,取消true;對于move事件按照水平滑動的閾值進行調(diào)整。但是這樣改動之后,還是只能水平滑動,不能垂直滑動。

這是因為ViewGroup中的返回true,直接使得onIntercept執(zhí)行,不可能通過dispatch傳到子View中,子View就不能通過設(shè)置disallow的flag。這也就是四個特性中的,需要注意讓【傳播鏈】形成。

改動2

改動ViewGroup的onInterceptTouchEvent,改動如下。不能攔截down事件,需要讓【傳播鏈】完成。這樣就可以左右滑動奏效了。


總結(jié)

  1. 事件傳遞過程主要有四個特性

    1. 事件逐級傳遞

    2. 上層ViewGroup可以通過onInterceptTouchEvent干預(yù)事件接收

    3. 傳播鏈形成后,后續(xù)事件按照傳播鏈傳播,不會重新構(gòu)建

    4. 傳播鏈形成后,可以通過子View設(shè)置disallowIntercept的flag

  2. 是這樣的傳播鏈

    1. action_down &?!intercept = false,此時傳播鏈沒有構(gòu)建mFirstTouchTarget=null,會調(diào)用View的方法(View這里會消費事件,并且應(yīng)該會返回true?我猜的)

    2. action_down &?!intercept = true,構(gòu)建view的列表,并且【遞歸】交給子view處理

    3. action_move 傳播鏈構(gòu)件好了,mFirstTouchTarget != null,返回true

????


Android 事件分發(fā)流程淺析的評論 (共 條)

分享到微博請遵守國家法律
定襄县| 修武县| 南涧| 禹州市| 吉水县| 永泰县| 吴江市| 三门峡市| 黄山市| 四子王旗| 奎屯市| 平远县| 永嘉县| 临夏市| 仁化县| 桂阳县| 赤峰市| 青铜峡市| 正安县| 安福县| 南江县| 抚松县| 思南县| 大连市| 绥江县| 白城市| 琼海市| 元江| 视频| 浮梁县| 南岸区| 财经| 黑河市| 常宁市| 渭源县| 调兵山市| 大足县| 玉树县| 张家口市| 县级市| 广丰县|