天天看點

Android事件分發機制之Activity(一)

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的事件分發流程就結束了。

繼續閱讀