view的事件分发使用

 
 
1.setOnTouchListener true   在OnTouchListener 的onTouch 处截断,不往下走,onTouchEvent 设置不起作用
    a.onTouchEvent false
         E/MyButton: dispatchTouchEvent ACTION_DOWN
         E/TAG: onTouch execute, action 0
         E/MyButton: dispatchTouchEvent ACTION_UP
         E/TAG: onTouch execute, action 1
    b.onTouchEvent true
        E/MyButton: dispatchTouchEvent ACTION_DOWN
        E/TAG: onTouch execute, action 0
         E/MyButton: dispatchTouchEvent ACTION_UP
         E/TAG: onTouch execute, action 1
1.setOnTouchListener false
    a.onTouchEvent false  走完第一次onTouchEvent,不在监听 dispatchTouchEvent ACTION_UP
         E/MyButton: dispatchTouchEvent ACTION_DOWN
         E/TAG: onTouch execute, action 0
         E/MyButton: onTouchEvent ACTION_DOWN
    b.onTouchEvent true
         E/MyButton: dispatchTouchEvent ACTION_DOWN
         E/TAG: onTouch execute, action 0
         E/MyButton: onTouchEvent ACTION_DOWN
         E/MyButton: dispatchTouchEvent ACTION_UP
         E/TAG: onTouch execute, action 1
         E/MyButton: onTouchEvent ACTION_UP

    c.onTouchEvent super.onTouchEvent(event)
        E/MyButton: dispatchTouchEvent ACTION_DOWN
        E/TAG: onTouch execute, action 0
        E/MyButton: onTouchEvent ACTION_DOWN
        E/MyButton: dispatchTouchEvent ACTION_UP
        E/TAG: onTouch execute, action 1
        E/MyButton: onTouchEvent ACTION_UP
        E/TAG: onClick execute
 */

 
 
 
 

View

1.   dispatchTouchEvent 

流程:1.mOnTouchListener.onTouch(this, event)   2. onTouchEvent(event)方法      3.onClick()

/**
 *  1.mOnTouchListener 不为空
    2.ENABLED可点击,
    2.onTouch(this, event)设置ture,对此事件处理(拦截)
    那么事件将不会继续往下分发
 */
if (li != null && li.mOnTouchListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
        && li.mOnTouchListener.onTouch(this, event)) {
    return true;
}

/**
 * 1. 如果mOnTouchListener不为空,  事件先在mOnTouchListener 的onTouch(this, event)处理了一遍
 * 2.  事件交由view的onTouchEvent方法处理,如果true,  那么事件将不会继续往下分发
 */
if (onTouchEvent(event)) {
    return true;
}
 

2.   onTouchEvent(event)

3.   public boolean onTouchEvent(MotionEvent event) {
    final int viewFlags = mViewFlags;


    if ((viewFlags & ENABLED_MASK) == DISABLED) {
        if (event.getAction() == MotionEvent.ACTION_UP && (mPrivateFlags & PFLAG_PRESSED) != 0) {
            setPressed(false);
        }
        // A disabled view that is clickable still consumes the touch
        // events, it just doesn't respond to them.
        /**
         *  1. 可点击,但是DISABLED,
         *  2.仍然消费touch事件,只是不作出回应。
         */
        return (((viewFlags & CLICKABLE) == CLICKABLE ||
                (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE));
    }

    if (mTouchDelegate != null) {
        if (mTouchDelegate.onTouchEvent(event)) {
            return true;
        }
    }

    if (((viewFlags & CLICKABLE) == CLICKABLE ||
            (viewFlags & LONG_CLICKABLE) == LONG_CLICKABLE)) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                /**
                 * 1.mPrivateFlags  包含PFLAG_PREPRESSED,或者包含PFLAG_PRESSED  则进入
                 *      115ms内或者之后抬起都会进入执行体。
                 *
                 */
                boolean prepressed = (mPrivateFlags & PFLAG_PREPRESSED) != 0;
                if ((mPrivateFlags & PFLAG_PRESSED) != 0 || prepressed) {
                    // take focus if we don't have it already and we should in
                    // touch mode.
                    boolean focusTaken = false;
                    if (isFocusable() && isFocusableInTouchMode() && !isFocused()) {
                        focusTaken = requestFocus();
                    }

                    if (prepressed) {
                        // The button is being released before we actually
                        // showed it as pressed.  Make it show the pressed
                        // state now (before scheduling the click) to ensure
                        // the user sees it.
                        setPressed(true);
                    }
                    /**
                     * 1.   没有执行长按,
                     *      或者没有监听,
                     *      或者 mOnLongClickListener.onLongClick(View.this)返回false
                     *       则移除 延时长按任务
                     * 2.   如果没有将点击任务加到队列中,则直接调用点击事件onClick
                     */
                    if (!mHasPerformedLongPress) {
                        // This is a tap, so remove the longpress check
                        removeLongPressCallback();

                        // Only perform take click actions if we were in the pressed state
                        if (!focusTaken) {
                            // Use a Runnable and post this rather than calling
                            // performClick directly. This lets other visual state
                            // of the view update before click actions start.
                            if (mPerformClick == null) {
                                mPerformClick = new PerformClick();
                            }
                            if (!post(mPerformClick)) {
                                performClick();
                            }
                        }
                    }
                    // 建立任务
                    //从 mPrivateFlags标签中 移除PFLAG_PRESSED
                    if (mUnsetPressedState == null) {
                        mUnsetPressedState = new UnsetPressedState();
                    }

                    if (prepressed) {
                        postDelayed(mUnsetPressedState,
                                ViewConfiguration.getPressedStateDuration());
                    } else if (!post(mUnsetPressedState)) {
                        // If the post failed, unpress right now
                        mUnsetPressedState.run();
                    }
                    //移除长按任务
                    removeTapCallback();
                }
                break;

            case MotionEvent.ACTION_DOWN:
                mHasPerformedLongPress = false;

                if (performButtonActionOnTouchDown(event)) {
                    break;
                }

                // Walk up the hierarchy to determine if we're inside a scrolling container.
                boolean isInScrollingContainer = isInScrollingContainer();

                // For views inside a scrolling container, delay the pressed feedback for
                // a short period in case this is a scroll.
                if (isInScrollingContainer) {
                    mPrivateFlags |= PFLAG_PREPRESSED;
                    if (mPendingCheckForTap == null) {
                        mPendingCheckForTap = new CheckForTap();
                    }
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                } else {
                    // Not inside a scrolling container, so show the feedback right away
                    setPressed(true);
                    checkForLongClick(0);
                }
                break;

            case MotionEvent.ACTION_CANCEL:
                setPressed(false);
                removeTapCallback();
                removeLongPressCallback();
                break;

            case MotionEvent.ACTION_MOVE:
                final int x = (int) event.getX();
                final int y = (int) event.getY();

                // Be lenient about moving outside of buttons
                /**
                 * 1.如果点击点在 view 范围内,进入执行体
                 * 2.标签是否 包含PFLAG_PRESSED  有 表明设置过,并有延时长按任务
                 * 3.移除长按任务
                 * 4.移除PFLAG_PRESSED
                 */
                if (!pointInView(x, y, mTouchSlop)) {
                    // Outside button
                    removeTapCallback();
                    if ((mPrivateFlags & PFLAG_PRESSED) != 0) {
                        // Remove any future long press/tap checks
                        removeLongPressCallback();

                        setPressed(false);
                    }
                }
                break;
        }
        return true;
    }

    return false;
}
 

猜你喜欢

转载自blog.csdn.net/dawan19909/article/details/78360874
今日推荐