android事件分发之view.onTouchEvent

这是android事件分法机制的最后一个重要的方法,一般自定义的视图都要往这里开刀,开个玩笑;ontouchevent方法消费事件的场合,无论消费的对象是viewgroup还是view都要调用该方法;那么默认的,view类在这个方法里做了什么呢?我们都知道OnClickListener和OnLongClickListener这两种事件监听器吧,对,你猜的不错,实现的机制就是在这个方法里面,让我们来看看吧。

第一步:分析viewFlags属性信息判断是否是可点击(clickable);第二步,如果当前的视图设置enable为false,但是视图是可点击的(clickable),我们还是认为它消费了该事件,否则是不消费,无论是否消费,在enable是false的情况下,它是直接返回的,也就不会响应onClick事件之类的;第三步,如果该视图将事件委托给了其他视图进行处理,那么让被委托的视图进行处理,自己就不处理了;接下来进入主题了:

//如果此视图是可点击的或者他的提示框是显示的,那么进入里面做进一步处理

if (clickable || (viewFlags & TOOLTIP) == TOOLTIP) {

    switch (action) {

        case MotionEvent.ACTION_UP:

            mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

          //如果是提示框显示,那么让他处理按起事件

            if ((viewFlags & TOOLTIP) == TOOLTIP) {

                handleTooltipUp();

            }

            if (!clickable) {

                removeTapCallback();

                removeLongPressCallback();

                mInContextButtonPress = false;

                mHasPerformedLongPress = false;

                mIgnoreNextUpEvent = false;

                break;

            }

          //记录该视图响应按下的事件

            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, x, y);

                }

//如果已经响应了长点击事件,那么就不响应点击事件

                if (!mHasPerformedLongPress && !mIgnoreNextUpEvent) {

                   // 移除长点击回调

                    removeLongPressCallback();

                    // Only perform take click actions if we were in the pressed state

                    if (!focusTaken) {

                    //响应点击事件

                        if (mPerformClick == null) {

                            mPerformClick = new PerformClick();

                        }

//执行点击操作

                        if (!post(mPerformClick)) {

                            performClick();

                        }

                    }

                }

                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();

            }

            mIgnoreNextUpEvent = false;

            break;

        case MotionEvent.ACTION_DOWN:

//如果是事件来源是触屏产生的,那么mPrivateFlags3标记为PFLAG3_FINGER_DOWN

            if (event.getSource() == InputDevice.SOURCE_TOUCHSCREEN) {

                mPrivateFlags3 |= PFLAG3_FINGER_DOWN;

            }

//重置为false

            mHasPerformedLongPress = false;

            if (!clickable) {

                checkForLongClick(0, x, y);

                break;

            }

            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) {

//按下时间大于taptimeout,那么进入长点击响应事件

                mPrivateFlags |= PFLAG_PREPRESSED;

                if (mPendingCheckForTap == null) {

                    mPendingCheckForTap = new CheckForTap();

                }

                mPendingCheckForTap.x = event.getX();

                mPendingCheckForTap.y = event.getY();

                postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());

            } else {

                // Not inside a scrolling container, so show the feedback right away

                setPressed(true, x, y);

                checkForLongClick(0, x, y);

            }

            break;

        case MotionEvent.ACTION_CANCEL:

            if (clickable) {

                setPressed(false);

            }

            removeTapCallback();

            removeLongPressCallback();

            mInContextButtonPress = false;

            mHasPerformedLongPress = false;

            mIgnoreNextUpEvent = false;

            mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

            break;

        case MotionEvent.ACTION_MOVE:

            if (clickable) {

                drawableHotspotChanged(x, y);

            }

            //超出视图大小范围,那么不会响应点击或长点击事件

            if (!pointInView(x, y, mTouchSlop)) {

                // Outside button

                // Remove any future long press/tap checks

                removeTapCallback();

                removeLongPressCallback();

                if ((mPrivateFlags & PFLAG_PRESSED) != 0) {

                    setPressed(false);

                }

                mPrivateFlags3 &= ~PFLAG3_FINGER_DOWN;

            }

            break;

    }

    return true;

}

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容