RecyclerView事件拦截

本文主要分析RecyclerView的onInterceptTouchEvent()对三种事件怎么处理的
这里只放了一些比较重要点的代码,有一部分省略

先看onInterceptTouchEvent()的返回值

return mScrollState == SCROLL_STATE_DRAGGING

解释一下mScrollState这个变量,代表RecyclerView的滑动状态,它一共有三种值

    public static final int SCROLL_STATE_IDLE = 0; // 滑动停止
    public static final int SCROLL_STATE_DRAGGING = 1; //正在被用户滑动
    public static final int SCROLL_STATE_SETTLING = 2;//正在自动滑动,这个大家日常应该都遇到过,当我们快速滑动然后抬起手时会发生自动滑动

ACTION_DOWN

   @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
         ...
        switch (action) {
            case MotionEvent.ACTION_DOWN:
             ...
                if (mScrollState == SCROLL_STATE_SETTLING) {
                    getParent().requestDisallowInterceptTouchEvent(true);
                    setScrollState(SCROLL_STATE_DRAGGING);
                    stopNestedScroll(TYPE_NON_TOUCH);
                }
                ...
                break;

             ...
        }
        
        return mScrollState == SCROLL_STATE_DRAGGING;
    }

down事件主要看中间的判断部分,如果当前的滑动状态是自动滑动(SCROLL_STATE_SETTLING)状态,则将滑动状态置为正在滑动(SCROLL_STATE_DRAGGING),然后停止滑动,这样就对down事件做了拦截,其实很好理解:当你的列表在自动快速滚动的过程中,手指再按上去,是需要停止滑动的;
所以只有这种情况RecyclerView才会拦截down事件,其他情况分发给子view

ACTION_MOVE

            case MotionEvent.ACTION_MOVE: {
               ...
                final int x = (int) (e.getX(index) + 0.5f);
                final int y = (int) (e.getY(index) + 0.5f);
                if (mScrollState != SCROLL_STATE_DRAGGING) {
                    final int dx = x - mInitialTouchX;
                    final int dy = y - mInitialTouchY;
                    boolean startScroll = false;
                    if (canScrollHorizontally && Math.abs(dx) > mTouchSlop) {
                        mLastTouchX = x;
                        startScroll = true;
                    }
                    if (canScrollVertically && Math.abs(dy) > mTouchSlop) {
                        mLastTouchY = y;
                        startScroll = true;
                    }
                    if (startScroll) {
                        setScrollState(SCROLL_STATE_DRAGGING);
                    }
                }
            } break;

move事件处理就很好理解了,如果当前滚动状态是正在滑动,就直接拦截;如果不是,则判断x轴和y轴上滑动距离是否超过最小滑动距离,超过了就将滚动状态置为正在滑动状态,然后拦截;

ACTION_UP

            case MotionEvent.ACTION_UP: {
                mVelocityTracker.clear();
                stopNestedScroll(TYPE_TOUCH);
            } break;

up事件除了停止滑动什么也没干,如果当前是正在滑动状态直接拦截,否则分发子view

总结

RecyclerView对三种事件的处理:
down事件:如果当前处于自动滚动状态,则拦截事件,停止滚动,否则分发给子view
move事件:如果当前处于正在滑动状态直接拦截,否则判断水平位置与竖直为滑动距离是否超过最小滑动距离(mTouchSlop),超过则拦截,否则不拦截
up事件:只做了停止滑动操作,是否拦截依赖当前滑动状态

你可能感兴趣的:(android)