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

本文探讨了解决嵌套RecyclerView与ViewPager滑动不畅的问题,通过自定义RecyclerView和覆盖LinearLayoutManager的canScrollVertically方法,实现流畅滑动。同时,分析了RecyclerView与ViewPager在事件分发上的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有些需求要在一个页面里面加好多东西,于是会出现嵌套RecyclerView,ViewPager的情况。
但是在嵌套之后,即使使用NestedScrollView也会出现一些问题,比如嵌套RecyclerView会出现滑动卡顿,嵌套ViewPager会出现在ViewPager区域无法上下滑动的问题。
1.先来说一下嵌套ViewPager无法上下滑动的问题
我的思路是可以在dispatchTouchEvent方法里面,在ACTION_DOWN的时候,记录下y坐标;然后在ACTION_MOVE的时候,通过y坐标的差值,来决定是自己处理,还是交给父控件

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方法里面,果然看到了

@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中进行处理就应该可以了。

/**
 * @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处理触摸事件,得具体分析,照搬可能是不行的

转载于:https://my.oschina.net/u/2606060/blog/2120658

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值