?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)流程。
屬性介紹
使用對象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ū)別)
流程圖如下:

屬性介紹
使用對象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);
流程圖如下:

屬性介紹
使用對象ViewGroup(注:Activity、View都沒該方法)
作用攔截事件,即自己處理該事件
調(diào)用時刻在ViewGroup的dispatchTouchEvent()內(nèi)部調(diào)用
返回結(jié)果是否攔截當(dāng)前事件,詳細(xì)情況如下:

流程圖如下:

3. 事件分發(fā)場景介紹
下面我將利用例子來說明常見的點(diǎn)擊事件傳遞情況
我們將要討論的布局層次如下:

最外層: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)生,然后用戶移動手指并最后離開屏幕。
一般的事件傳遞場景有:
默認(rèn)情況
處理事件
攔截DOWN事件
攔截后續(xù)事件(MOVE、UP)
即不對控件里的方法(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的行為是不一樣的。
假設(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()

假設(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)用了。

假設(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()