Android事件分發機制算是Android高級篇的基礎了,程序猿一定要對其有所瞭解。
(1)確定事件分發的對象
當用戶點擊View或ViewGroup時就產生了觸摸(Touch)事件,Touch相關的細節被封裝成了MotionEvent
對象。當我們自定義View時經常重寫onTouchEvent
方法,比如:
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
break;
case MotionEvent.ACTION_MOVE:
break;
case MotionEvent.ACTION_CANCEL:
break;
case MotionEvent.ACTION_UP:
break;
}
return super.onTouchEvent(event);
}
onTouchEvent
可以監聽到觸摸(Touch)事件。
常用的Touch事件有四種:
- MotionEvent.ACTION_DOWN:按下View
- MotionEvent.ACTION_MOVE:滑動View
- MotionEvent.ACTION_CANCEL:非人爲原因取消事件
- MotionEvent.ACTION_UP:擡起View
View事件的基本流程是:
用戶按下View,觸發ACTION_DOWN
事件-->用戶拖動或滾動View,觸發ACTION_MOVE
事件-->用戶擡起,放開View,觸發ACTION_UP
事件。
ACTION_CANCEL
事件的觸發非人爲觸發,也許是程序猿代碼中主動取消,也許是發生了異常導致取消。
(2)事件分發的本質
本質上是將點擊時間的出來傳遞到View本身去處理,這個過程叫做分發過程。
(3)事件傳遞的載體
事件傳遞的載體是:Activity(Window)、ViewGroup、View。
假設點擊一個按鈕,事件的傳遞順序是:Activity(Window)-->ViewGroup-->View
下圖是Activity、ViewGroup、View的層級圖,其實Activity上面還有一層叫PhoneWindow
,但不是本章重點。
請先記住觸摸事件的傳遞順序:Activity(Window)-->ViewGroup-->View
- Activity:它是Android界面的基本
- ViewGroup:有線性佈局、相對佈局、約束佈局、幀佈局、表格佈局、RecyclerView、其它自定義ViewGroup
- View:比如,TextView、ImageView或者其它自定義View
(4)事件的分發由哪些方法協調?
事件的分發由dispatchTouchEvent()
、onInterceptTouchEvent()
、onTouchEvent()
相互協調的。
-
onTouchEvent()
:負責處理觸摸事件
事件分發到最後,總是由 onTouchEvent()
來處理觸摸事件。
它的返回值代表的意義:
[true]
:直接結束
[super或false]
:執行上級的onTouchEvent()
方法
-
dispatchTouchEvent()
:負責分發觸摸事件
事件的分發總是由這個方法開始,根據不同的返回值做出相應的處理:
[true]
:直接結束事件的分發
[false]
:執行上級的onTouchEvent()
方法去處理觸摸事件,最後結束事件的分發
[super]
:繼續分發事件
-
onInterceptTouchEvent()
:負責攔截觸摸事件
只有在ViewGroup中才有這個方法,這個方法專門負責事件的攔截工作,根據返回值處理不同的結果:
[true]
:執行ViewGroup的onTouchEvent()
事件;
[super或false]
:執行View的dispatchTouchEvent()
方法
(5)事件在Activity中是如何處理的?
前提條件:Activity中有一個按鈕(View),按鈕在一個佈局(ViewGroup)中。
我們都知道觸摸事件的傳遞順序:Activity(Window)-->ViewGroup-->View
,那麼在Activity中事件是如何處理的呢?
Activity中有一個dispatchTouchEvent
方法,當有觸摸事件時,最先執行的方法就是dispatchTouchEvent
,它的返回類型是一個boolean類型,默認情況下返回super.dispatchTouchEvent(ev)
,當返回super.dispatchTouchEvent(ev)
時,事件將傳遞給ViewGroup,但是如果返回true或者false時,事件就會直接結束,不會傳遞給ViewGrou,更不會傳遞給View。
比如,在Activity中重寫dispatchTouchEvent
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return true;
}
或
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return false;
}
這種情況下,按鈕是不可能監聽到點擊事件的,一般我們不會在Activity中重寫dispatchTouchEvent
方法,就默認返回super.dispatchTouchEvent(ev)
,讓它把事件傳遞到ViewGroup即可。
(6)事件在ViewGroup中是如何處理的?
當事件從Activity傳遞到ViewGroup之後,ViewGroup是如何處理這個事件的呢?
在ViewGroup中,事件首先被分發到ViewGroup的dispatchTouchEvent
方法:
- 如果返回true則直接結束分發;
- 如果返回false,則執行Activity的
onTouchEvent
方法,Activity的onTouchEvent
方法不管返回什麼都直接結束分發; - 如果返回
super.dispatchTouchEvent(ev)
,則執行onInterceptTouchEvent
方法;
onInterceptTouchEvent
的返回值解析如下:
- 如果返回true,則執行ViewGroup的
onTouchEvent
方法; - 如果返回super或者false,則執行View的
dispatchTouchEvent
方法;
onTouchEvent
的返回值解析如下:
- 返回true,直接結束事件
- 否則,執行Activity的
onTouchEvent
方法
(7)事件在View中是如何處理的?
在View中,事件首先被分發到View的dispatchTouchEvent
方法:
- 返回true,結束事件
- 返回false,執行ViewGroup的
onTouchEvent
方法 - 返回super,則直接執行View的
onTouchEvent
方法
(8)事件分發流程圖(是重點,要記住)
以上這張圖要記住,上面說了那麼多廢話,記不住不要緊,只要將這張圖記住就可以了。
(9)總結
- 請記住以上的一張圖,因爲這張圖纔是世間分發機制的精髓所在,其實這張圖就是事件分發機制的全部了;
- 事件分發機制是實現自定義View的基礎,所以一定要了解;
- 現在很多嵌套View都存在觸摸事件衝突問題,這時就需要事件分發機制的知識來解決這個問題了。
[本章完...]