Android中的dispatchTouchEvent()、onInterceptTouchEvent()和onTouchEvent()

對象

  • Activity
  • View
  • ViewGroup

內容

  • dispatchTouchEvent()
  • onInterceptTouchEvent()
  • onTouchEvent()

     在Android 中,視圖的概念其實就是View,存放由多個View組成的視圖組的載體就是ViewGroup,最後把視圖或者視圖組的呈現給使用者的載體,就是大家所熟悉的Activity。然而在當下觸屏的電子產品時代,對於一個Android開發者而言,觸碰事件的基礎也將不在僅僅是基礎了。
    基礎了。

  • dispatchTouchEvent:處理觸碰事件的分發,執行super.dispatchTouchEvent(ev),事件向下分發。

  • onInterceptTouchEvent:ViewGroup提供的方法,默認返回false,返回true表示攔截。
  • onTouchEvent:默認返回true,表示消費了這個事件。

Activity裏,有兩個回調函數

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent event);

View裏,有兩個回調函數

public boolean dispatchTouchEvent(MotionEvent ev);    
public boolean onTouchEvent(MotionEvent event);

ViewGroup裏,有三個回調函數

public boolean dispatchTouchEvent(MotionEvent ev);
public boolean onInterceptTouchEvent(MotionEvent ev);     
public boolean onTouchEvent(MotionEvent event);

Activity

  Android中通常點擊事件用MotionEvent來表示,當一個點擊操作發生時,事件最先傳遞給當前的Activity,由Activity的dispatchTouchEvent來進行事件的分發,具體工作是由Activity內部的Window來完成的。Window會將事件傳遞給decorview,decorview一般就是當前界面的底層容器(即setContentView所設置的View的父容器),通過Activity.getWindow.getDecorView()可以獲得。關於Activity事件分發機制的源碼,我們重點來看下dispatchTouchEvent和onTouchEvent方法。
dispatchTouchEvent

實現類Activity的dispatchTouchEvent方法,用來做Log信息跟蹤:
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        String motionEventInfo = "";
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                motionEventInfo = "ACTION_DOWN";
                break;
            case MotionEvent.ACTION_MOVE:
                motionEventInfo = "ACTION_MOVE";
                break;
            case MotionEvent.ACTION_UP:
                motionEventInfo = "ACTION_UP";
                break;
            default:
                motionEventInfo = ev.getAction() + "";
                break;
        }
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : motionEventInfo = " + motionEventInfo);

        //事件一開始就由Activity所附屬的Window進行分發,
        //如果返回true,整個事件循環就結束了,不在走onTouchEvent流程,
        //如果返回false意味着事件沒人處理,所有事件往下分發給onTouchEvent來處理,
        //如果最後所有View的onTouchEvent都返回了false,那麼Activity就要來做最後的收場。
        boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev);
        Log.e(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = " + isSuperDispatchTouchEvent);
        boolean isNext = super.dispatchTouchEvent(ev);
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : isNext = " + isNext);
        return true;
    }

基類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();
        }

        //事件一開始就由Activity所附屬的Window進行分發,
        //如果返回true,整個事件循環就結束了,不在走onTouchEvent流程,
        //如果返回false意味着事件沒人處理,所有事件往下分發給onTouchEvent來處理,
        //如果最後所有View的onTouchEvent都返回了false,那麼Activity就要來做最後的收場。
        if (getWindow().superDispatchTouchEvent(ev)) {
            return true;
        }
        //分發給onTouchEvent處理,
        return onTouchEvent(ev);
    }

boolean isSuperDispatchTouchEvent = getWindow().superDispatchTouchEvent(ev)是boolean isNext = super.dispatchTouchEvent(ev)中的內容:
1、事件一開始就由Activity所附屬的Window進行分發
2、如果isSuperDispatchTouchEvent 值爲true,那麼就super.dispatchTouchEvent(ev)就直接return true不在往下執行onTouchEvent事件,意味着事件的結束
3、如果isSuperDispatchTouchEvent 值爲false,那麼事件就會往下被分發到onTouchEvent中處理
4、Activity的onTouchEvent是最後來消化其他子View沒有處理的touch事件

onTouchEvent

實現類的onTouchEvent方法,用來做Log信息跟蹤:
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        String motionEventInfo = "";
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                motionEventInfo = "ACTION_DOWN";
                break;
            case MotionEvent.ACTION_MOVE:
                motionEventInfo = "ACTION_MOVE";
                break;
            case MotionEvent.ACTION_UP:
                motionEventInfo = "ACTION_UP";
                break;
            default:
                motionEventInfo = event.getAction() + "";
                break;
        }
        Log.d(GlobalUtils.TAG, "[MainActivity] dispatchTouchEvent : onTouchEvent = " + motionEventInfo);
        //目前還不清楚mWindow.shouldCloseOnTouch(this, event)的具體源碼
        boolean isNext = super.onTouchEvent(event);
        Log.d(GlobalUtils.TAG, "[MainActivity] onTouchEvent : isNext = " + isNext);
        return isNext;
    }
基類Activity的onTouchEvent的源碼:
    /**
     * Called when a touch screen event was not handled by any of the views
     * under it.  This is most useful to process touch events that happen
     * outside of your window bounds, where there is no view to receive it.
     *
     * @param event The touch screen event being processed.
     *
     * @return Return true if you have consumed the event, false if you haven't.
     * The default implementation always returns false.
     */
    public boolean onTouchEvent(MotionEvent event) {
        if (mWindow.shouldCloseOnTouch(this, event)) {
            finish();
            return true;
        }

        return false;
    }

Activity的onTouchEvent算是Android 應用層上最後用來消化點擊事件的最後防線了,然而對於super.onTouchEvent(event)中的mWindow.shouldCloseOnTouch(this, event)事件,目前還不清楚具體的作用,因爲目前跟蹤不到其內部源碼。
總結:

Log信息如下:

04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_DOWN
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.307 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : motionEventInfo = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle E/dfsu: [MainActivity] dispatchTouchEvent : Window.SuperDispatchTouchEvent = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : onTouchEvent = ACTION_UP
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] onTouchEvent : isNext = false
04-04 21:23:15.367 12682-12682/com.sdf.aso.viewlifecycle D/dfsu: [MainActivity] dispatchTouchEvent : isNext = false



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章