一、筆記連結

1. android 觸控事件傳遞機制

2. android OnTouchListener,onTouchEvent,onClickListener執行順序 

二、簡記

1. android 觸控事件傳遞機制

1.1Touch事件分發中只有兩個主角:ViewGroup和View。ViewGroup包含onInterceptTouchEvent、dispatchTouchEvent、onTouchEvent三個相關事件。View包含dispatchTouchEvent、onTouchEvent兩個相關事件。其中ViewGroup又繼承於View。

1.2.ViewGroup和View組成了一個樹狀結構,根節點為Activity內部包含的一個ViwGroup。

1.3.觸控事件由Action_Down、Action_Move、Aciton_UP組成,其中一次完整的觸控事件中,Down和Up都只有一個,Move有若干個,可以為0個。

1.4.當Acitivty接收到Touch事件時,將遍歷子View進行Down事件的分發。ViewGroup的遍歷可以看成是遞迴的。分發的目的是為了找到真正要處理本次完整觸控事件的View,這個View會在onTouchuEvent結果返回true。

1.5.當某個子View返回true時,會中止Down事件的分發,同時在ViewGroup中記錄該子View。接下去的Move和Up事件將由該子View直接進行處理。

/**
     * ViewGroup
     * @param ev
     * @return
     */
    public boolean dispatchTouchEvent(MotionEvent ev){
        ....//其他處理,在此不管
        View[] views=getChildView();
        for(int i=0;i<views.length;i++){
           //判斷下Touch到螢幕上的點在該子View上面 
            if(...){
            if(views[i].dispatchTouchEvent(ev))
              return true;
             }
        }
        ...//其他處理,在此不管
    }
    /**
     * View
     * @param ev
     * @return
     */
    public boolean dispatchTouchEvent(MotionEvent ev){
        ....//其他處理,在此不管
        return false;
    }
要特別注意FrameLayout中子view的觸控事件傳遞:預設情況下(即不消費觸控事件),重疊的多個view都會接收到觸控事件

FrameLayout 例項1(評論是重點)例項2

2. android OnTouchListener,onTouchEvent,onClickListener執行順序 

首先執行OnTouchListener,之後為onTouchEvent,最後才執行onClickListener內的方法

public boolean dispatchTouchEvent(MotionEvent event) {
        ......
        ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }
        if (!result && onTouchEvent(event)) {
            result = true;
        }
        ......
        return result;
    }
public boolean onTouchEvent(MotionEvent event) {
        ......
        switch (action) {
             case MotionEvent.ACTION_UP:
                  ......
                  performClick();
                  ......
                  break;
        ......
    }

public boolean performClick() {
        final boolean result;
        final ListenerInfo li = mListenerInfo;
        if (li != null && li.mOnClickListener != null) {
            playSoundEffect(SoundEffectConstants.CLICK);
            li.mOnClickListener.onClick(this);
            result = true;
        } else {
            result = false;
        }
        sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);
        return result;
    }