Android事件分發機制的原理簡單講就是從使用者點選螢幕開始,從螢幕上移動,最後擡起的過程,主要包括:按下(down)、移動(move)、擡起(up),将這些操作觸發的事件交給具體的View處理的過程。
事件分發包含的主要方法有:
1、dispatchTouchEvent(進行事件分發)
2、onInterceptTouchEvent(判斷是否攔截事件,此方法隻在ViewGroup中)
3、onTouchEvent(處理事件)
事件分發的順序:Activity --> ViewGroup --> View
這篇主要講的是事件分發在Activity中的執行流程,具體結合源碼來看:
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
onUserInteraction();
}
if (getWindow().superDispatchTouchEvent(ev)) {
return true;
}
return onTouchEvent(ev);
}
事件分發從Activity的dispatchTouchEvent開始,首先第一個if條件判斷是否是按下操作,一般事件分發都是從按下操作開始執行,進入onUserInteraction方法中可以看到裡面什麼都沒寫,但是從注釋上可以看出,使用者可以重寫這個方法,用來判斷使用者在此activity上是不是觸發了點選操作。
再看第二個if條件,getWindow()指的就是Window對象,我們來看下這個對象的superDispatchTouchEvent方法
public abstract boolean superDispatchTouchEvent(MotionEvent event);
可以看到這是一個抽象方法,接下來直接看Window唯一的實作類PhoneWindow怎麼寫的這個方法
@Override
public boolean superDispatchTouchEvent(MotionEvent event) {
return mDecor.superDispatchTouchEvent(event);
}
看到這裡,我們會想mDecor又是什麼呢?其實它就是DecorView,它裡面的實作是這樣的
public boolean superDispatchTouchEvent(MotionEvent event) {
return super.dispatchTouchEvent(event);
}
最後我們檢視super.dispatchTouchEvent可以發現,調用的是ViewGroup裡面的dispatchTouchEvent方法,由此我們可以知道事件從Activity傳遞到了ViewGroup,再回到剛才Activity的dispatchTouchEvent方法看,如果第二個if條件傳回了true,事件被消費,那麼不會執行Activity的onTouchEvent方法,事件分發到此結束,反之,如果傳回的是false,事件沒有被消費,則會交給Activity的onTouchEvent方法處理。
再來看下Activity的onTouchEvent方法:
public boolean onTouchEvent(MotionEvent event) {
if (mWindow.shouldCloseOnTouch(this, event)) {
finish();
return true;
}
return false;
}
if條件裡面調用了Window的shouldCloseOnTouch方法,如果此方法傳回true,則會退出Activity并傳回true,否則傳回false,事件分發到此結束。我們看下Window的shouldCloseOnTouch方法源碼:
public boolean shouldCloseOnTouch(Context context, MotionEvent event) {
if (mCloseOnTouchOutside && event.getAction() == MotionEvent.ACTION_DOWN
&& isOutOfBounds(context, event) && peekDecorView() != null) {
return true;
}
return false;
}
1)mCloseOnTouchOutsize是由android:windowCloseOnTouchOutside屬性值決定的;
2)如果是按下操作;
3)判斷點選事件是否在context(目前Activity)之外,如果是傳回true,否則傳回false;
4)peekDecorView()傳回的是PhoneWindow的mDecor
是以最後這個方法的意思是:如果android:windowCloseOnTouchOutside屬性為true,并且目前觸摸事件是ACTION_DOWN,且該觸摸事件在Activity之外,同時Activity包含了視圖,則傳回true,否則傳回false。接到上面說的onTouchEvent方法,如果if條件傳回true,則Activity退出,而這個傳回值就是由shouldCloseOnTouch方法決定的。
到此,Activity的事件分發流程就結束了。