竖直滑动的RecyclerView嵌套竖直滑动的RecyclerView并解决滑动冲突

项目中要求两个红框区域列表滑动时吸顶,头像部分超过四行可上下滑动。

问题①两个区域吸顶实现:这个比较好实现,我是在页面根布局RelativeLayout中写了两个跟吸顶布局一样的View,然后通过监听RecyclerView滑动距离控制RelativeLayout中两个布局的显示和隐藏。代码如下:

        productRV.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int[] peopleRegionLoc = new int[2];
                peopleRegion.getLocationOnScreen(peopleRegionLoc);
                int peopleRegionLocX = peopleRegionLoc[0];
                int peopleRegionLocY = peopleRegionLoc[1];

                if (isStickTuan == false && peopleRegionLocY <= tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this)) {
                    isStickTuan = true;
                    tuanLyStick.setVisibility(View.VISIBLE);
                } else if (isStickTuan && peopleRegionLocY > tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this)) {
                    tuanLyStick.setVisibility(View.INVISIBLE);
                    isStickTuan = false;
                }

                int[] grayRegionLoc = new int[2];
                grayRegion.getLocationOnScreen(grayRegionLoc);
                int grayRegionLocX = grayRegionLoc[0];
                int grayRegionLocY = grayRegionLoc[1];

                if (isStickTab == false && grayRegionLocY <= tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this) - ScreenUtils.dip2px(HomeZutuanActivity.this, 10)) {
                    isStickTab = true;
                    tabLyStick.setVisibility(View.VISIBLE);
                } else if (isStickTab && grayRegionLocY > tuanLy.getHeight() + topTitleView.getHeight() + StatusBarUtil.getStatusBarHeight(HomeZutuanActivity.this) - ScreenUtils.dip2px(HomeZutuanActivity.this, 10)) {
                    tabLyStick.setVisibility(View.INVISIBLE);
                    isStickTab = false;
                }
            }
        });

问题②:RecyclerView嵌套的RecyclerView也要实现可上下滑动。首先我写了最基本的嵌套代码,发现内层RecyclerView根本无法滑动,设置setFocusable也是然并卵。当时第一想法就是先去网上找找有没有类似效果,经过一番搜索以失败而告终。没有办法,只能硬着头皮自己解决滑动冲突。隐隐约约记得之前看过一篇ScrollView嵌套ScrollView的文章(https://mp.weixin.qq.com/s/2-LVR0vTDDLoHQAt7Y4CCw),再次品味突然恍然大悟,自己心里默默地 ao 了一声,原来也不过如此嘛。

解决滑动冲突原理其实就是:当我们想让内层滑动时在onTouchEvent中设置getParent().requestDisallowInterceptTouchEvent(true);这样控制父View不拦截滑动事件,进而让内层获得焦点滑动。当内层RecyclerView滑动到底部了我们要让外层滑动,设置etParent().requestDisallowInterceptTouchEvent(false);并返回false 不消耗事件。具体代码如下:

public class NestRecyclerView extends RecyclerView {

    private int lastVisibleItemPosition;
    private int firstVisibleItemPosition;
    private float mLastY = 0;// 记录上次Y位置
    private boolean isTopToBottom = false;
    private boolean isBottomToTop = false;
    public NestRecyclerView(Context context) {
        this(context, null);
    }

    public NestRecyclerView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public NestRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    /*@Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        int action = ev.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.onInterceptTouchEvent(ev);
    }*/

    @Override
    public boolean dispatchTouchEvent(MotionEvent event) {
        int action = event.getAction();
        switch (action) {
            case MotionEvent.ACTION_DOWN:
                mLastY = event.getY();
                //不允许父View拦截事件
                getParent().requestDisallowInterceptTouchEvent(true);
                break;
            case MotionEvent.ACTION_MOVE:
                float nowY = event.getY();
                isIntercept(nowY);
                if (isBottomToTop||isTopToBottom){
                    getParent().requestDisallowInterceptTouchEvent(false);
                    return false;
                }else{
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                mLastY = nowY;
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                getParent().requestDisallowInterceptTouchEvent(false);
                break;
        }
        return super.onTouchEvent(event);
    }

    private void isIntercept(float nowY){

        isTopToBottom = false;
        isBottomToTop = false;

        RecyclerView.LayoutManager layoutManager = getLayoutManager();
        if (layoutManager instanceof GridLayoutManager) {
            //得到当前界面,最后一个子视图对应的position
            lastVisibleItemPosition = ((GridLayoutManager) layoutManager)
                    .findLastVisibleItemPosition();
            //得到当前界面,第一个子视图的position
            firstVisibleItemPosition = ((GridLayoutManager) layoutManager)
                    .findFirstVisibleItemPosition();
        }
        //得到当前界面可见数据的大小
        int visibleItemCount = layoutManager.getChildCount();
        //得到RecyclerView对应所有数据的大小
        int totalItemCount = layoutManager.getItemCount();
        LogUtils.d("nestScrolling","onScrollStateChanged");
        if (visibleItemCount>0) {
            if (lastVisibleItemPosition == totalItemCount - 1) {
                //最后视图对应的position等于总数-1时,说明上一次滑动结束时,触底了
                LogUtils.d("nestScrolling", "触底了");
                if (NestRecyclerView.this.canScrollVertically(-1) && nowY < mLastY) {
                    // 不能向上滑动
                    LogUtils.d("nestScrolling", "不能向上滑动");
                    isBottomToTop = true;
                } else {
                    LogUtils.d("nestScrolling", "向下滑动");
                }
            } else if (firstVisibleItemPosition == 0) {
                //第一个视图的position等于0,说明上一次滑动结束时,触顶了
                LogUtils.d("nestScrolling", "触顶了");
                if (NestRecyclerView.this.canScrollVertically(1) && nowY > mLastY) {
                    // 不能向下滑动
                    LogUtils.d("nestScrolling", "不能向下滑动");
                    isTopToBottom = true;
                } else {
                    LogUtils.d("nestScrolling", "向上滑动");
                }
            }
        }
    }


}

这个是我重写的RecyclerView解决了嵌套的滑动冲突,喜欢的小伙伴可以直接拿去用。

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值