天天看點

Android的時間分發機制 完整解析

在Android的觸摸點選等事件中我們經常需要用到時間分發機制,看了很多朋友寫的部落格,感覺不是很明朗,綜合多家的精粹用通俗的描述全面的介紹下事件分發機制。

1。首先來一張全局圖

Android的時間分發機制 完整解析

1代表我們的activity

2代表我們的viewgroup 也就是我們經常說的容器

3 就是最頂層的view了 比偶如說 textview imageview等

先簡單的介紹下,稍後再代碼分析

當點選最頂層的view的時候

down事件經過: activity的分發機制函數 dispatchTouchEvent 當傳回true或者false的時候事件就在分發中就會被消費,不會傳到上一層,也不會執行activity的 onTouchEvent

/**
     * 事件的分發
     * 分發事件的方法。當接收到事件時,通過調用此方法來決定是否分發。
     * @param ev
     * @return
     *  true: 事件不再進行分發且已經在自身事件的分發中被消費
     *  false: 也不對事件進行分發。
     *  也就是說該方法不論是傳回true還是傳回false都不會對事件進行分發,
     *
     *  隻有當傳回系統預設super.dispatchTouchEvent(ev)時,才會将事件分發給本層
     *  的攔截事件onInterceptTouchEvent(MotionEvent ev)去處理,如果沒有onInterceptTouchEvent(MotionEvent ev)方法
     *  則直接分發給子View中的onInterceptTouchEvent(MotionEvent ev)方法處理
     *
     */
    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if(ev.getAction() == MotionEvent.ACTION_DOWN){
            Log.d("data","[LinearLayout]--dispatchTouchEvent:"+ev.getAction()+"     "+super.dispatchTouchEvent(ev));
        }
        return super.dispatchTouchEvent(ev);
    }
	/*log日志
    *EventActivity: dispatchTouchEvent=====ACTION_DOWN
    *EventActivity: dispatchTouchEvent=====ACTION_UP
    */
           

activity的 dispatchTouchEvent傳回super.dispatchTouchEvent(ev)的時候事件往下傳遞進入viewgroup的分發機制中,

如果viewgroup的 dispatchTouchEvent傳回true/false的時候,事件不會被往下分發,而是回傳到activity的onTouchEvent去消費事件,在activity中的onTouchEvent執行完事件後如果傳回true表示消費了這個事件,傳遞到此結束,傳回false表示不處理事件,繼續分發,此時事件就丢失了

如果viewgroup的 dispatchTouchEvent傳回super.dispatchTouchEvent(ev);的時候,down事件就會繼續繼續向上傳遞,到達View頂層的dispatchTouchEvent,如果View的dispatchTouchEvent傳回true/false的時候,事件會傳遞給viewgroup的onTouchEvent去消費事件,隻有傳回super.dispatchTouchEvent(ev);才會調用本層的onTouchEvent,如果本層onTouchEvent傳回true,事件到此結束,相當于消耗了事件。如果傳回false的話,接下來的move和up事件将不會配置設定給View,而是直接在viewgroup的onTouchEvent去消費事件。

ViewGroup特有的時間攔截 onInterceptTouchEvent

/**
     * 事件的攔截
     * 攔截事件方法,該方法隻有在布局或者ViewGroup中才會有。通過調用該方法來決定是否對事件
     * 進行攔截。
     * @param ev
     * @return
     *  true:進行攔截,将事件進行分發onTouchEvent方法處理
     *  false:不對事件進行攔截,傳遞給下一級處理
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if(ev.getAction() ==MotionEvent.ACTION_DOWN){
            Log.d("data","[LinearLayout]--onInterceptTouchEvent:"+ev.getAction()+"     "+super.onInterceptTouchEvent(ev));
        }
        return super.onInterceptTouchEvent(ev);
    }

           

事件處理函數

/**
     * 事件的處理
     * 處理事件。當對事件進行了攔截時,将會調用onTouchEvent方法對事件進行處理。
     *
     * @param ev
     * @return
     *  true:表示該View能處理該事件,事件将終止向上傳遞(傳遞給其父View)
     *  false:不能處理,則把事件傳遞給其父View的onTouchEvent方法來處理
     */
    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if(ev.getAction() ==MotionEvent.ACTION_DOWN){
            Log.d("data","[LinearLayout]--onTouchEvent:"+ev.getAction()+"     "+super.onTouchEvent(ev));
        }
        return super.onTouchEvent(ev);
    }
    //注意:onTouchEvent事件消費函數一旦傳回false 後面的滑鼠UP 和 MOVE 就不會在這裡執行了,但是下一次down事件能擷取到
           

Android中的事件在表現形式上有很多,如onTouch、onClick和onLongClick等,在具體微觀上的表現形式有action_down、action_move和action_up等。但是不管是哪種表現形式,都是基于事件的傳遞。