Android 事件分發(fā)機(jī)制

?1、目錄

1、基礎(chǔ)認(rèn)知

????1.1 事件分發(fā)的對象是誰?

? ??????答:事件

????????當(dāng)用戶觸摸屏幕時(View或ViewGroup派生的控件),將產(chǎn)生點(diǎn)擊事件(Touch事件)。

????????Touch事件相關(guān)細(xì)節(jié)(發(fā)生觸摸的位置、時間、歷史記錄、手勢動作等)被封裝成MotionEvent對象

????????主要發(fā)生的Touch事件有如下四種:

????????MotionEvent.ACTION_DOWN:按下View(所有事件的開始)

????????MotionEvent.ACTION_MOVE:滑動View

????????MotionEvent.ACTION_CANCEL:非人為原因結(jié)束本次事件

????????MotionEvent.ACTION_UP:抬起View(與DOWN對應(yīng))

????????事件列:從手指接觸屏幕至手指離開屏幕,這個過程產(chǎn)生的一系列事件

????????任何事件列都是以DOWN事件開始,UP事件結(jié)束,中間有無數(shù)的MOVE事件,如下圖:

????????即當(dāng)一個MotionEvent 產(chǎn)生后,系統(tǒng)需要把這個事件傳遞給一個具體的 View 去處理,

????1.2 事件分發(fā)的本質(zhì)

????? ??答:將點(diǎn)擊事件(MotionEvent)向某個View進(jìn)行傳遞并最終得到處理

????????即當(dāng)一個點(diǎn)擊事件發(fā)生后,系統(tǒng)需要將這個事件傳遞給一個具體的View去處理。這個事件傳遞的過程就? ????????發(fā)過程。

? ??1.3 事件在哪些對象之間進(jìn)行傳遞?

? ??????答:Activity、ViewGroup、View

????????一個點(diǎn)擊事件產(chǎn)生后,傳遞順序是:Activity(Window) -> ViewGroup -> View

????????Android的UI界面是由Activity、ViewGroup、View及其派生類組合而成的

????View是所有UI組件的基類

????一般Button、ImageView、TextView等控件都是繼承父類View

????ViewGroup是容納UI組件的容器,即一組View的集合(包含很多子View和子VewGroup),

????其本身也是從View派生的,即ViewGroup的父類是View

????是Android所有布局的父類或間接父類:項目用到的布局(LinearLayout、RelativeLayout等),都繼承自? ? ? ? ? ViewGroup,即屬于ViewGroup子類。

????與普通View的區(qū)別:ViewGroup實際上也是一個View,只不過比起View,它多了可以包含子View和定義布? ? ? ? 局參數(shù)的功能。

????Activity是ViewGrou的子類、ViewGroup是View的子類

?1.4 事件分發(fā)過程由哪些方法協(xié)作完成?

? ??答:dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()

????????1.5 總結(jié)

? ? Android事件分發(fā)機(jī)制的本質(zhì)是要解決:點(diǎn)擊事件由哪個對象發(fā)出,經(jīng)過哪些對象,最終? ? ? ??? 達(dá)到哪個對象并最終得到處理。

? ? 這里的對象是指Activity、ViewGroup、View

????Android中事件分發(fā)順序:Activity(Window) -> ViewGroup -> View

? ?事件分發(fā)過程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三個方? ? ? ?法協(xié)助完成

????經(jīng)過上述3個問題,相信大家已經(jīng)對Android的事件分發(fā)有了感性的認(rèn)知,接下來,我將詳細(xì)? ? ? 介紹Android事? ? ? ? 件分發(fā)機(jī)制。

2. 事件分發(fā)機(jī)制方法&流程介紹

事件分發(fā)過程由dispatchTouchEvent() 、onInterceptTouchEvent()和onTouchEvent()三個方法協(xié)助完成,如下圖:

Android事件分發(fā)流程如下:(必須熟記

Android事件分發(fā)順序:Activity(Window) -> ViewGroup -> View

其中:

super:調(diào)用父類方法

true:消費(fèi)事件,即事件不繼續(xù)往下傳遞

false:不消費(fèi)事件,事件也不繼續(xù)往下傳遞 / 交由給父控件onTouchEvent()處理

接下來,我將詳細(xì)介紹這3個方法及相關(guān)流程。

2.1 dispatchTouchEvent()

屬性介紹

使用對象Activity、ViewGroup、View

作用分發(fā)點(diǎn)擊事件

調(diào)用時刻當(dāng)點(diǎn)擊事件能夠傳遞給當(dāng)前View時,該方法就會被調(diào)用

返回結(jié)果是否消費(fèi)當(dāng)前事件,詳細(xì)情況如下:

1. 默認(rèn)情況:根據(jù)當(dāng)前對象的不同而返回方法不同

對象返回方法備注

Activity????super.dispatchTouchEvent()????即調(diào)用父類ViewGroup的dispatchTouchEvent()

ViewGroup????onIntercepTouchEvent()????即調(diào)用自身的onIntercepTouchEvent()

View????onTouchEvent()????即調(diào)用自身的onTouchEvent()


2. 返回true

消費(fèi)事件

事件不會往下傳遞

后續(xù)事件(Move、Up)會繼續(xù)分發(fā)到該View

流程圖如下:

3. 返回false

不消費(fèi)事件

事件不會往下傳遞

將事件回傳給父控件的onTouchEvent()處理

Activity例外:返回false=消費(fèi)事件

后續(xù)事件(Move、Up)會繼續(xù)分發(fā)到該View(與onTouchEvent()區(qū)別)

流程圖如下:

2.2 onTouchEvent()

屬性介紹

使用對象Activity、ViewGroup、View

作用處理點(diǎn)擊事件

調(diào)用時刻在dispatchTouchEvent()內(nèi)部調(diào)用

返回結(jié)果是否消費(fèi)(處理)當(dāng)前事件,詳細(xì)情況如下:

與dispatchTouchEvent()類似

1. 返回true

自己處理(消費(fèi))該事情

事件停止傳遞

該事件序列的后續(xù)事件(Move、Up)讓其處理;

流程圖如下:

2. 返回false(同默認(rèn)實現(xiàn):調(diào)用父類onTouchEvent())

不處理(消費(fèi))該事件

事件往上傳遞給父控件的onTouchEvent()處理

當(dāng)前View不再接受此事件列的其他事件(Move、Up);

流程圖如下:

2.3 onInterceptTouchEvent()

屬性介紹

使用對象ViewGroup(注:Activity、View都沒該方法)

作用攔截事件,即自己處理該事件

調(diào)用時刻在ViewGroup的dispatchTouchEvent()內(nèi)部調(diào)用

返回結(jié)果是否攔截當(dāng)前事件,詳細(xì)情況如下:

流程圖如下:

3. 事件分發(fā)場景介紹

下面我將利用例子來說明常見的點(diǎn)擊事件傳遞情況

3.1 背景描述

我們將要討論的布局層次如下:

最外層:Activiy A,包含兩個子View:ViewGroup B、View C

中間層:ViewGroup B,包含一個子View:View C

最內(nèi)層:View C

假設(shè)用戶首先觸摸到屏幕上View C上的某個點(diǎn)(如圖中黃色區(qū)域),那么Action_DOWN事件就在該點(diǎn)產(chǎn)生,然后用戶移動手指并最后離開屏幕。

3.2 一般的事件傳遞情況

一般的事件傳遞場景有:

默認(rèn)情況

處理事件

攔截DOWN事件

攔截后續(xù)事件(MOVE、UP)

3.2.1 默認(rèn)情況

即不對控件里的方法(dispatchTouchEvent()、onTouchEvent()、onInterceptTouchEvent())進(jìn)行重寫或更改返回值

那么調(diào)用的是這3個方法的默認(rèn)實現(xiàn):調(diào)用父類的方法

事件傳遞情況:(如圖下所示)

從Activity A—->ViewGroup B—>View C,從上往下調(diào)用dispatchTouchEvent()

再由View C—>ViewGroup B —>Activity A,從下往上調(diào)用onTouchEvent()

注:雖然ViewGroup B的onInterceptTouchEvent方法對DOWN事件返回了false,后續(xù)的事件(MOVE、UP)依然會傳遞給它的onInterceptTouchEvent()

這一點(diǎn)與onTouchEvent的行為是不一樣的。

3.2.2 處理事件

假設(shè)View C希望處理這個點(diǎn)擊事件,即C被設(shè)置成可點(diǎn)擊的(Clickable)或者覆寫了C的onTouchEvent方法返回true。

最常見的:設(shè)置Button按鈕來響應(yīng)點(diǎn)擊事件

事件傳遞情況:(如下圖)

DOWN事件被傳遞給C的onTouchEvent方法,該方法返回true,表示處理這個事件

因為C正在處理這個事件,那么DOWN事件將不再往上傳遞給B和A的onTouchEvent();

該事件列的其他事件(Move、Up)也將傳遞給C的onTouchEvent()

3.2.3 攔截DOWN事件

假設(shè)ViewGroup B希望處理這個點(diǎn)擊事件,即B覆寫了onInterceptTouchEvent()返回true、onTouchEvent()返回true。

事件傳遞情況:(如下圖)

DOWN事件被傳遞給B的onInterceptTouchEvent()方法,該方法返回true,表示攔截這個事件,即自己處理這個事件(不再往下傳遞)

調(diào)用onTouchEvent()處理事件(DOWN事件將不再往上傳遞給A的onTouchEvent())

該事件列的其他事件(Move、Up)將直接傳遞給B的onTouchEvent()

該事件列的其他事件(Move、Up)將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調(diào)用了。

3.2.4 攔截DOWN的后續(xù)事件

假設(shè)ViewGroup B沒有攔截DOWN事件(還是View C來處理DOWN事件),但它攔截了接下來的MOVE事件。

DOWN事件傳遞到C的onTouchEvent方法,返回了true。

在后續(xù)到來的MOVE事件,B的onInterceptTouchEvent方法返回true攔截該MOVE事件,但該事件并沒有傳遞給B;這個MOVE事件將會被系統(tǒng)變成一個CANCEL事件傳遞給C的onTouchEvent方法

后續(xù)又來了一個MOVE事件,該MOVE事件才會直接傳遞給B的onTouchEvent()

后續(xù)事件將直接傳遞給B的onTouchEvent()處理

后續(xù)事件將不會再傳遞給B的onInterceptTouchEvent方法,該方法一旦返回一次true,就再也不會被調(diào)用了。

C再也不會收到該事件列產(chǎn)生的后續(xù)事件。

特別注意:

如果ViewGroup A 攔截了一個半路的事件(如MOVE),這個事件將會被系統(tǒng)變成一個CANCEL事件并傳遞給之前處理該事件的子View;

該事件不會再傳遞給ViewGroup A的onTouchEvent()

只有再到來的事件才會傳遞到ViewGroup A的onTouchEvent()

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容