Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> Android編程入門 >> Android view 的事件分發機制

Android view 的事件分發機制

編輯:Android編程入門

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 進行處理。

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

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved