View的事件分发基本过程

基本过程

  1. View事件分发的原理是责任链模式,事件层层传递,直到被消费。

  2. 从Activity->PhoneWindow->DecorView->ViewGroup->View
    ,在传递的过程中判断是否要拦截事件,不拦截则交给子View处理

  3. 子View判断是否设置了OnTouchListener,根据onTouch的返回值决定是否要执行onTouchEvent

  4. 最终如果事件被子View消费了则结束本次事件分发,如果没有被消费则从子View的父容器到Activity依次调用super.dispatchTouchEvent(即ViewGroup的父类View的dispatchTouchEvent方法,与第3步过程一样)

View的dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent event) {
    ...
    boolean result = false; // result 为返回值,主要作用是告诉调用者事件是否已经被消费。
    if (onFilterTouchEventForSecurity(event)) {
        ListenerInfo li = mListenerInfo;
        /** 
         * 如果设置了OnTouchListener,并且当前 View 可点击,就调用监听器的 onTouch 方法,
         * 如果 onTouch 方法返回值为 true,就设置 result 为 true。
         */
        if (li != null && li.mOnTouchListener != null
                && (mViewFlags & ENABLED_MASK) == ENABLED
                && li.mOnTouchListener.onTouch(this, event)) {
            result = true;
        }
      
        /** 
         * 如果 result 为 false,则调用自身的 onTouchEvent。
         * 如果 onTouchEvent 返回值为 true,则设置 result 为 true。
         */
        if (!result && onTouchEvent(event)) {
            result = true;
        }
    }
    ...
    return result;
}

onTouchEvent

public boolean onTouchEvent(MotionEvent event) {
    ...
    final int action = event.getAction();
    // 检查各种 clickable
    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE) ||
            (viewFlags & CONTEXT_CLICKABLE) == CONTEXT_CLICKABLE) {
        switch (action) {
            case MotionEvent.ACTION_UP:
                ...
                removeLongPressCallback();  // 移除长按
                ...
                performClick();             // 检查单击
                ...
                break;
            case MotionEvent.ACTION_DOWN:
                ...
                checkForLongClick(0);       // 检测长按
                ...
                break;
            ...
        }
        return true;                        // ◀︎表示事件被消费
    }
    return false;
}

ViewGroup的dispatchTouchEvent

public boolean dispatchTouchEvent(MotionEvent ev) {
    boolean result = false;             // 默认状态为没有消费过

    if (!onInterceptTouchEvent(ev)) {   // 如果没有拦截交给子View
        result = child.dispatchTouchEvent(ev);
    }

    if (!result) {                      // 如果事件没有被消费,询问自身onTouchEvent
    //通过调用super.dispatchTouchEvent
        result = onTouchEvent(ev);
    }

    return result;
}

reference

安卓自定义View进阶-事件分发机制详解

你可能感兴趣的:(View的事件分发基本过程)