Android view 的事件分發機制

來源:互聯網
上載者:User

標籤:

1 事件的行程順序是 Activity -> Window -> 頂層View

touch 事件產生後,最先由 activity 的 dispatchTouchEvent 處理

  /**     * Called to process touch screen events.  You can override this to     * intercept all touch screen events before they are dispatched to the     * window.  Be sure to call this implementation for touch screen events     * that should be handled normally.     *     * @param ev The touch screen event.     *     * @return boolean Return true if this event was consumed.     */    public boolean dispatchTouchEvent(MotionEvent ev) {        if (ev.getAction() == MotionEvent.ACTION_DOWN) {            onUserInteraction();        }        if (getWindow().superDispatchTouchEvent(ev)) {            return true;        }        return onTouchEvent(ev);    }

接著事件會傳到 Window 的 superDispatchTouchEvent。 如果所有的 view 都沒有消費事件,最後會交給 activity 的 onTouchEvent 處理。

2 Window 是一個抽象類別,它的唯一實作類別是 PhoneWindow

/** * Abstract base class for a top-level window look and behavior policy.  An * instance of this class should be used as the top-level view added to the * window manager. It provides standard UI policies such as a background, title * area, default key processing, etc. * * <p>The only existing implementation of this abstract class is * android.view.PhoneWindow, which you should instantiate when needing a * Window. */public abstract class Window {
}

查看 PhoneWindow 的 superDispatchTouchEvent

public boolean superDispatchTouchEvent(MotionEvent event) {            return mDecor.superDispatchTouchEvent(event);    }

調用了 mDecor 的 superDispatchTouchEvent

private final class DecorView extends FrameLayout implements RootViewSurfaceTaker {}// This is the top-level view of the window, containing the window decor.private DecorView mDecor;

mDecor 就是 DecorView, DecorView 是一個 FrameLayout, 就是我們 setContentView 所設定 view 的父容器。

繼續看 DecorView 的superDispatchTouchEvent

public boolean superDispatchTouchEvent(MotionEvent event) {    return super.dispatchTouchEvent(event);}

調用了父類的 dispatchTouchEvent,  FrameLayout 中沒有 dispatchTouchEvent, 實際上調用了 FrameLayout 的父類 ViewGroup 的 dispatchTouchEvent。

到此事件就傳遞到了頂層View(ViewGroup) 中,接著事件就從頂層 view 開始向子view分發。

3 事件分發主要涉及 3 個方法

public boolean dispatchTouchEvent(MotionEvent event)

事件傳遞到一個 view 時就會先調用這個 view 的 dispatchTouchEvent 進行往下分發

public boolean onInterceptTouchEvent(MotionEvent ev)

進行事件的攔截,只有 ViewGroup 有攔截方法, 單一View沒有,事件傳到 單一View 就直接調用 onTouchEvent 進行處理了

public boolean onTouchEvent(MotionEvent event)

處理點擊事件,true 表示消費這個事件, false 表示不消費

4 下面的虛擬碼可以很好的說明事件的分發過程

public boolean dispatchTouchEvent(MotionEvent ev) {    boolean consume = false;    if (onInterceptTouchEvent(ev)) {        consume = onTouchEvent(ev);    }else {        consume = child.dispatchTouchEvent(ev);    }        return consume;}

事件傳遞到頂層 ViewGroup 中後, 就會調用 ViewGroup dispatchTouchEvent 進行分發。如果這個 ViewGroup 的 onInterceptTouchEvent 返回 True 表是它要攔截這個事件,接著就會調用它的 onTouchEvent 進行處理。如果不攔截則會交給它的子 view 繼續進行分發, 如此反覆直到事件被最終處理。

正常情況下,一個事件序列只能被一個 view 攔截且消耗。一個 view 一旦攔截了某個事件,那麼同一個事件序列內的所有的事件都會交給它處理。

如果一個 view 的 onTouchEvent 返回 false, 那麼它的父容器的 onTouchEvent 將會被調用,依次類推。如果所有的 view 都不處理這個事件,這個事件最後會返回到 activity 的 onTouchEvent 進行處理。

事件分發具體細節較為複雜,但基本流程就是上面的虛擬碼。事件分發機制是處理滑動衝突的根本,知道了原理,遇到問題再多看看源碼就行了。

  

Android view 的事件分發機制

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.