返回介绍

事件拦截

发布于 2024-12-23 21:14:47 字数 4425 浏览 0 评论 0 收藏 0

touch 事件会先被 onInterceptTouchEvent() 捕获,进行判断是否拦截。

@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
    if (!child.isShown()) {
        return false;
    }
    int action = MotionEventCompat.getActionMasked(event);
    // Record the velocity
    if (action == MotionEvent.ACTION_DOWN) {
        reset();
    }
    if (mVelocityTracker == null) {
        mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);
    switch (action) {
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            mTouchingScrollingChild = false;
            mActivePointerId = MotionEvent.INVALID_POINTER_ID;
            // Reset the ignore flag
            if (mIgnoreEvents) {
                mIgnoreEvents = false;
                return false;
            }
            break;
        case MotionEvent.ACTION_DOWN:
            int initialX = (int) event.getX();
            mInitialY = (int) event.getY();
            View scroll = mNestedScrollingChildRef.get();
            if (scroll != null && parent.isPointInChildBounds(scroll, initialX, mInitialY)) {
                mActivePointerId = event.getPointerId(event.getActionIndex());
                mTouchingScrollingChild = true;
            }
            mIgnoreEvents = mActivePointerId == MotionEvent.INVALID_POINTER_ID &&
                    !parent.isPointInChildBounds(child, initialX, mInitialY);
            break;
    }
    if (!mIgnoreEvents && mViewDragHelper.shouldInterceptTouchEvent(event)) {
        return true;
    }
    // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because
    // it is not the top most view of its parent. This is not necessary when the touch event is
    // happening over the scrolling content as nested scrolling logic handles that case.
    View scroll = mNestedScrollingChildRef.get();
    return action == MotionEvent.ACTION_MOVE && scroll != null &&
            !mIgnoreEvents && mState != STATE_DRAGGING &&
            !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY()) &&
            Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop();
}

onInterceptTouchEvent 做了几件事情:

  1. 判断是否拦截事件.先使用 mViewDragHelper.shouldInterceptTouchEvent(event) 拦截。
  2. 使用 mVelocityTracker 记录手指动作,用于后期计算 Y 轴速率。
  3. 判断点击事件是否在 NestedChildView 上,将 boolean 存到 mTouchingScrollingChild 标记位中,这个主要是用于 ViewDragHelper.Callback 中的判断。
  4. ACTION_UP 和 ACTION_CANCEL 对标记位进行复位,好在下一轮 Touch 事件中使用。

onTouchEvent 处理

 @Override
    public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
        if (!child.isShown()) {
            return false;
        }
        int action = MotionEventCompat.getActionMasked(event);
        if (mState == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {
            return true;
        }
        mViewDragHelper.processTouchEvent(event);
        // Record the velocity
        if (action == MotionEvent.ACTION_DOWN) {
            reset();
        }
        if (mVelocityTracker == null) {
            mVelocityTracker = VelocityTracker.obtain();
        }
        mVelocityTracker.addMovement(event);
        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it
        // to capture the bottom sheet in case it is not captured and the touch slop is passed.
        if (action == MotionEvent.ACTION_MOVE) {
            if (Math.abs(mInitialY - event.getY()) > mViewDragHelper.getTouchSlop()) {
                mViewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));
            }
        }
        return true;
    }

onTouchEvent 主要做了几件事情:

  1. 使用 mVelocityTracker 记录手指动作.用于后期计算 Y 轴速率。
  2. 使用 mViewDragHelper 处理 Touch 事件.可能会产生拖动效果。
  3. mViewDragHelper 在滑动的时候对 BehaviorView 的再一次捕获.再一次明确告诉 ViewDragHelper 我要移动的是 BehaviorView 组件.什么情况需要主动告诉 ViewDragHelper ?比如:当你点击在 BehaviorView 的区域,但是 BehaviorView 的视图的层级不是最高的,或者你点击的区域不在 BehaviorView 上,ViewDragHelper 在做处理滑动的时候找不到 BehaviorView, 这个时候你要手动告知它现在要移动的是 BehaviorView,情景类似 ViewDragHelper 处理 EdgeDrag 的样子。

注意:即使你的 onInterceptTouchEvent 返回 false,也可能因为下面的 View 没有处理这个 Touch 事件,而导致 Touch 事件上发被 Behavior 的 onTouchEvent 被截取。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文