分析ScrollView嵌套RecyclerView、ViewPager引起的滑动问题

有些需求要在一个页面里面加好多东西,因而会出现嵌套RecyclerView,ViewPager的状况。
可是在嵌套以后,即便使用NestedScrollView也会出现一些问题,好比嵌套RecyclerView会出现滑动卡顿,嵌套ViewPager会出如今ViewPager区域没法上下滑动的问题。
1.先来讲一下嵌套ViewPager没法上下滑动的问题
个人思路是能够在dispatchTouchEvent方法里面,在ACTION_DOWN的时候,记录下y坐标;而后在ACTION_MOVE的时候,经过y坐标的差值,来决定是本身处理,仍是交给父控件ide

public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downY = ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (Math.abs(ev.getY() - downY) > 50) {
                    getParent().requestDisallowInterceptTouchEvent(false);
                    return false;
                }
                break;
        }

这样经过事件分发,把事件拦截交给父控件,能够解决没法上下滑动的问题。
2.再来讲说嵌套RecyclerView出现滑动卡顿的问题
我按照处理ViewPager的方法,想去解决RecyclerView的问题,结果发现这样不行,会产生好多问题。
而后查资料发现一个很简单的方法,覆写LinearLayoutManager的canScrollVertically方法,return false禁止竖直方向的滑动,试了一下果真能够,滑的很顺畅。
既然问题解决了,那么为何一样的方法,能够解决ViewPager的问题,对RecyclerView却不行呢?
既然canScrollVertically方法能够解决,那么我想能够从源码中找canScrollVerticall方法的相关,就能够找出来答案了。就去看了一下源码,果真找到了答案。
源码那么多,怎么找呢?我想既然是触摸滑动的问题,那么应该逃不出分发(dispatchTouchEvent)、拦截(onInterceptTouchEvent)、处理(onTouchEvent)的那三个关于触摸的方法,就在RecyclerView里面搜索canScrollVertically,定位到dispatchTouchEvent方法里面,果真看到了spa

@Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        ...无关代码省略...

        switch (action) {
            case MotionEvent.ACTION_DOWN:
                 ...无关代码省略...

                int nestedScrollAxis = ViewCompat.SCROLL_AXIS_NONE;
                if (canScrollHorizontally) {
                    nestedScrollAxis |= ViewCompat.SCROLL_AXIS_HORIZONTAL;
                }
                if (canScrollVertically) {
                    nestedScrollAxis |= ViewCompat.SCROLL_AXIS_VERTICAL;
                }
                startNestedScroll(nestedScrollAxis, TYPE_TOUCH);
                break;
			......

            case MotionEvent.ACTION_MOVE: {
                 ...无关代码省略...
                if (mScrollState != SCROLL_STATE_DRAGGING) {
                     ...无关代码省略...
                }
            } break;

             ...无关代码省略...
        }
        return mScrollState == SCROLL_STATE_DRAGGING;
    }

原来在RecyclerView中,对滑动事件的方法,是在ACTION_DOWN中进行的。
那么若是自定义RecyclerView的话,只要在ACTION_DOWN中进行处理就应该能够了。code

/**
 * @author zhangyi
 * @date 2018/9/21
 * 解决嵌套RecycleView出现滑动卡顿的问题
 */
public class NestedRecycleView extends RecyclerView {
    public NestedRecycleView(Context context) {
        super(context);
    }

    public NestedRecycleView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }

    public NestedRecycleView(Context context, @Nullable AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent e) {
        if (e.getAction()== MotionEvent.ACTION_DOWN) {
            return false;
        }
        return super.onInterceptTouchEvent(e);
    }


        @Override
    public boolean onTouchEvent(MotionEvent e) {
        if (e.getAction()== MotionEvent.ACTION_DOWN) {
            //这个得加上,表明本身处理点击事件,否则点击item会没反应
            return true;
        }
        return super.onTouchEvent(e);
    }
}

看来对不一样的View处理触摸事件,得具体分析,照搬多是不行的事件

相关文章
相关标签/搜索