Android之解决RecyclerView与NestedScrollView的滑动冲突方法

news2024/9/20 20:47:58

1、解决RecyclerView与NestedScrollView的滑动冲突

问题一:当我们滑动RecyclerView组件时,上方的轮播图并没有进行滑动(NestedScrollView没有滑动,即滑动事件被RecyclerView消费了),当RecyclerView滑到底时,轮播图部分才进行滑动。 如下图,RecyclerView已经进行了滑动,但轮播图部分没有。
在这里插入图片描述
整体布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:AutoLoopStyle="http://schemas.android.com/apk/res-auto"
    android:id="@+id/home_pager_parent"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@color/color_page_Bg"
    android:gravity="center"
    android:orientation="vertical">


        <!--滚动页面-->
        <androidx.core.widget.NestedScrollView
            android:id="@+id/home_pager_nested_scroller"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:overScrollMode="never">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:gravity="center"
                android:orientation="vertical">

                <LinearLayout
                    android:id="@+id/home_pager_header_container"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"

                    android:orientation="vertical">

                    <RelativeLayout
                        android:layout_width="match_parent"
                        android:layout_height="125dp"
                        android:layout_marginBottom="14dp">

                        <com.example.taobaounion.ui.custom.AutoLoopViewPager
                            android:id="@+id/looper_pager"
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            AutoLoopStyle:duration="4000"
                            android:overScrollMode="never" />

                        <LinearLayout
                            android:id="@+id/looper_point_container"
                            android:layout_width="match_parent"
                            android:layout_height="wrap_content"
                            android:layout_alignParentBottom="true"
                            android:layout_marginBottom="10dp"
                            android:gravity="center"
                            android:orientation="horizontal" />

                    </RelativeLayout>
                    <!--标题-->
                    <include layout="@layout/include_home_pager_title_part"
                        />

                </LinearLayout>




                <androidx.recyclerview.widget.RecyclerView
                    android:id="@+id/home_pager_content_list"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"

                    android:overScrollMode="never" />


            </LinearLayout>


        </androidx.core.widget.NestedScrollView>



</LinearLayout>

这并不符合我们的设计要求,我们希望让轮播图先滑到顶部,然后才进行RecycleView的滑动。在recycleView中有个方法使用recyclerView.setNestedScrollingEnabled(false); 即可解决滑动冲突。进行测试


    @BindView(R.id.home_pager_content_list)
    public RecyclerView mContentList;
    @Override
    protected void initView(View rootView) {

        mContentList.setNestedScrollingEnabled(false);  //没错,就是我了
    }

测试后发现可行,但是出现了另一个问题,当轮播图部分滑动出屏幕时,就不能继续向上滑动了。 如下图,此时无论是NestedScrollView还是RecyclerView都不能再继续向上滑动了。
在这里插入图片描述
基于这个现象,我猜测recyclerView.setNestedScrollingEnabled(false)方法实际上让NestedScrollView不再将滑动事件继续向下分发,而是独自消费了这个事件。那么由于NestScrollView的高度限制(轮播图的高度和recyclerView的item高度),以及RecyclerView没有收到滑动事件(不能继续更新item数据),因此此时不能再继续向上滑动。 如果我的猜测正确,那么要解决这个问题只需要在合适的时机让NestedScrollView将事件分发给RecyclerView,即在合适的时机调用mContentList.setNestedScrollingEnabled(true)即可。 于是我在HomePagerFragment类的initListener()方法中,为NestedScrollView设置了监听器,根据其滑动的距离为其设置是否独自消费事件

   //尝试解决滑动冲突
    mNestedScrollView.setOnScrollChangeListener(new NestedScrollView.OnScrollChangeListener() {
        @Override
        public void onScrollChange(NestedScrollView v, int scrollX, int scrollY, int oldScrollX, int oldScrollY) {
            LogUtils.e(HomePagerFragment.class,"NestedScrollView --> scrollY -->" + scrollY);
	    //滑动的距离大于或等于mContentList的顶部位置时
            if (scrollY >= mContentList.getTop()) mContentList.setNestedScrollingEnabled(true);
            else mContentList.setNestedScrollingEnabled(false);
        }
    });

测试结果:可行,滑动冲突解决,但是仍存在一些瑕疵。

2、解决刷新控件冲突

解决了滑动冲突之后,把刷新控件增加进来,这里1为了修改刷新组件的源代码,将它的模块依赖添加到项目中
项目地址:github地址
在这里插入图片描述
在这里插入图片描述

发现再次出现了问题。 如下图,还没拉到底呢,你怎么就给我加载更多了呢
在这里插入图片描述
道理是一样的,因为刷新组件TwinklingRefreshLayout消耗了事件,RecyclerView并没有收到事件,所以出现了这种情况。 解决的方法就是在刷新组件消耗事件的方法中进行判断,如果RecyclerView还能进行滑动,那就不消耗这个事件,将事件分发给RecyclerView,否则就消耗这个事件,进行数据的加载。
通过观察源码发现RefreshProcessor类重写了dispatchTouchEvent方法,如下代码所示

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downEventSent = false;
                intercepted = false;
                mTouchX = ev.getX();
                mTouchY = ev.getY();

                if (cp.isEnableKeepIView()) {
                    if (!cp.isRefreshing()) {
                        cp.setPrepareFinishRefresh(false);
                    }
                    if (!cp.isLoadingMore()) {
                        cp.setPrepareFinishLoadMore(false);
                    }
                }

                cp.dispatchTouchEventSuper(ev);
                return true;
            case MotionEvent.ACTION_MOVE:
                mLastMoveEvent = ev;
                float dx = ev.getX() - mTouchX;
                float dy = ev.getY() - mTouchY;
                if (!intercepted && Math.abs(dx) <= Math.abs(dy) && Math.abs(dy) > cp.getTouchSlop()) {//滑动允许最大角度为45度
                    if (dy > 0 && ScrollingUtil.isViewToTop(cp.getTargetView(), cp.getTouchSlop()) && cp.allowPullDown()) {
                        cp.setStatePTD();
                        mTouchX = ev.getX();
                        mTouchY = ev.getY();
                        sendCancelEvent();
                        intercepted = true;
                        return true;
                    } else if (dy < 0 && ScrollingUtil.isViewToBottom(cp.getTargetView(), cp.getTouchSlop()) && cp.allowPullUp()) {
                        cp.setStatePBU();
                        mTouchX = ev.getX();
                        mTouchY = ev.getY();
                        intercepted = true;
                        sendCancelEvent();
                        return true;
                    }
                }
                if (intercepted) {
                    if (cp.isRefreshVisible() || cp.isLoadingVisible()) {
                        return cp.dispatchTouchEventSuper(ev);
                    }
                    if (!cp.isPrepareFinishRefresh() && cp.isStatePTD()) {
                        if (dy < -cp.getTouchSlop() || !ScrollingUtil.isViewToTop(cp.getTargetView(), cp.getTouchSlop())) {
                            cp.dispatchTouchEventSuper(ev);
                        }
                        dy = Math.min(cp.getMaxHeadHeight() * 2, dy);
                        dy = Math.max(0, dy);
                        cp.getAnimProcessor().scrollHeadByMove(dy);
                    } else if (!cp.isPrepareFinishLoadMore() && cp.isStatePBU()) {
                        //加载更多的动作
                        if (dy > cp.getTouchSlop() || !ScrollingUtil.isViewToBottom(cp.getTargetView(), cp.getTouchSlop())) {
                            cp.dispatchTouchEventSuper(ev);
                        }
                        dy = Math.max(-cp.getMaxBottomHeight() * 2, dy);
                        dy = Math.min(0, dy);
                        cp.getAnimProcessor().scrollBottomByMove(Math.abs(dy));
                    }
                    if (dy == 0 && !downEventSent) {
                        downEventSent = true;
                        sendDownEvent();
                    }
                    return true;
                }
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                if (intercepted) {
                    if (cp.isStatePTD()) {
                        willAnimHead = true;
                    } else if (cp.isStatePBU()) {
                        willAnimBottom = true;
                    }
                    intercepted = false;
                    return true;
                }
                break;
        }
        return cp.dispatchTouchEventSuper(ev);
    }

在这里插入图片描述
这里的isViewToBottom方法中的getTargetView就是拿到我们包裹在TwinklingRefreshLayout刷新控件里的内容
再看看isViewToBottom方法

    public static boolean isViewToBottom(View view, int mTouchSlop) {
        if (view instanceof AbsListView) return isAbsListViewToBottom((AbsListView) view);
        if (view instanceof RecyclerView) return isRecyclerViewToBottom((RecyclerView) view);
        if (view instanceof WebView) return isWebViewToBottom((WebView) view, mTouchSlop);
        if (view instanceof ViewGroup) return isViewGroupToBottom((ViewGroup) view);
        return false;
    }

这个方法判断刷新组件中的子容器是什么类型,并根据类型调用不同的方法,我们添加一段判断子容器是NestedScrollView的语句,注意要写在判断ViewGroup类型的上面。

        if (view instanceof NestedScrollView) return isNestedScrollViewToBottom((NestedScrollView)view);//这段是我添加的

根据之前的分析完成方法

  private static boolean isNestedScrollViewToBottom(NestedScrollView view) {
        ViewGroup viewGroup = (ViewGroup) view.getChildAt(0); //根据布局文件知道这其实是一个LinearLayout
        RecyclerView recyclerView = null;
        //找到LinearLayout中的RecyclerView
        for (int i = 0; i < viewGroup.getChildCount(); i++) {
            if (viewGroup.getChildAt(i) instanceof RecyclerView)
                recyclerView = (RecyclerView) viewGroup.getChildAt(i);
        }
        //如果RecyclerView能继续向上滑动,则不消费这个事件
        //recyclerView.canScrollVertically(1))表示是否可以向上滑动
        if (recyclerView != null && recyclerView.canScrollVertically(1)) return false;
        //否则消费该事件
        return true;
    }

至此,刷新控件冲突就解决了。不过这个方法并没有经过细细的打磨,因此还存在着一些问题。比如最后实现的方法实际上并不完善,它只能在刷新组件中仅有一个RecyclerView的情况下才能正常使用。不过也是一种解决问题的思路

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/594790.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Nginx的搭建和优化

目录 一. Nginx简介1.1 概述1.2 Nginx和Apache优缺点比较 二. Nginx编译安装步骤1 关闭防火墙&#xff0c;安装依赖包2. 创建运行用户和组3. 编译安装 Nginx4. 做软连接并启动nginx5. 停止Nginx6. 添加nginx系统服务方法一&#xff1a;编写脚本方法二 将nginx命令加入服务 7. 查…

高完整性系统工程(四):Formal Verification and Validation

目录 1. Specification Process 1.1 State Invariants 1.2 Exceptional Behaviour 1.3 Framing 1.4 Summary 2. V&V FOR SPECS 2.1 V&V for formal specs 2.2 Proof 2.3 Proof Assistants 2.4 Model Checking 1. Specification Process Specification Proces…

1128 N Queens Puzzle(21行代码)

分数 20 全屏浏览题目 切换布局 作者 CHEN, Yue 单位 浙江大学 The "eight queens puzzle" is the problem of placing eight chess queens on an 88 chessboard so that no two queens threaten each other. Thus, a solution requires that no two queens sha…

QTranslator Class

QTranslator Class QTranslator 类公共成员函数类说明查找翻译使用多种翻译成员函数使用说明 QTranslator 类 QTranslator类为文本输出提供国际化支持。多国语言 Header: #include <QTranslator> qmake: QT core Inherits: QObject公共成员函数 构造函数QTranslator(…

代码随想录算法训练营15期 Day 7 | 454.四数相加II 、 383. 赎金信 、15. 三数之和 、18. 四数之和

昨天看了一下别的东西&#xff0c;导致昨天没有练习打卡&#xff0c;今天补上昨天的学习知识。 454.四数相加II 建议&#xff1a;本题是 使用map 巧妙解决的问题&#xff0c;好好体会一下 哈希法 如何提高程序执行效率&#xff0c;降低时间复杂度&#xff0c;当然使用哈希法 会…

AURIX TC3XX Cached PFLASH与Non-Cached PFLASH的区别

Cached ? Non-Cached&#xff1f; 在阅读TC3XX的用户手册时&#xff0c;在内存映射表中&#xff0c;有两个segment都是Program Flash&#xff0c;而且大小都一样是3M&#xff0c;一个是segment 8 另一个是segment10 这难免让人产生疑惑&#xff0c;二者区别在哪&#xff1f; …

高程实验 二分算法

学校的ppt把相等也考虑到大于上面去了&#xff0c;所以是错误的 1. (程序题) 有n(1<n<1000005)个整数&#xff0c;已经按照从小到大顺序排列好&#xff0c;现在另外给一个整数x&#xff0c;请找出序列中第1个大于x的数的下标&#xff01; 输入&#xff1a; 输入数据包含多…

4. 垃圾收集器ParNewCMS底层三色标记算法详解

JVM性能调优 1. 垃圾收集算法1.1 分代收集理论1.2 标记-复制算法1.3 标记-清除算法1.4 标记-整理算法 2. 垃圾收集器2.1 Serial收集器(-XX:UseSerialGC -XX:UseSerialOldGC)2.2 Parallel Scavenge收集器(-XX:UseParallelGC(年轻代)&#xff0c;-XX:UseParallelOldGC(老年代))2.…

浅谈MySQL主键

常用主键 常用主键 1&#xff09;自增 int、bigint等&#xff0c;顺序递增。 2&#xff09;雪花 雪花算法是因为有时间参数&#xff0c;所以是有序地&#xff0c;而且都是由数字组成。雪花id最大为64位,符合java中long的长度64位&#xff0c;适用于大规模分布式场景。 3&#…

docker基础操作与进阶 - 搭建基于pm2的node环境

1、为什么要使用docker 最近遇到一台机器需要部署两个不同版本node的情况&#xff0c;首先就想起了docker&#xff0c;想必还有其他类似环境问题的情况&#xff0c;需要进行项目隔离&#xff0c;而docker正是用来解决这个问题的。 docker的优势就在于环境隔离&#xff0c;相当…

第九篇、基于Arduino uno,用LCD1602(带IIC的)显示屏显示字符——结果导向

0、结果 说明&#xff1a;可以在LCD1602屏幕上面显示字符&#xff0c;实时的变量&#xff0c;也可以设置是否背光&#xff0c;如果是你想要的&#xff0c;可以接着往下看。 1、外观 说明&#xff1a;注意是带IIC通讯的LCD屏幕&#xff0c;外形如下。 2、连线 说明&#xff…

Hexo写文章不方便?用上GitHub Actions真的是泰裤辣

对于做个人博客的小伙伴来说 HEXO 大家肯定都是非常熟悉的吧,这是一个静态的个人博客程序,通过 HEXO + GitHub Pages 搭建免费个人博客也是很多博主的选择。但相信肯定也会有些困恼,比如博客的渲染维护太麻烦了,我要在一台新设备上写博客并推送到 GitHub Pages 还要先安装 …

【Redis】聊一下哨兵集群

上一篇中&#xff0c;介绍了哨兵机制可以减少主库实例下线的误判率&#xff0c;但是如果只有一个哨兵实例&#xff0c;出现宕机后没有办法保证服务的高可用&#xff0c;所以一般实际的生产环境都是搭建3个哨兵实例构建的集群进行运行。但是具体的运行机制是什么。其实主要就是三…

使用langchain及llama_index实现基于文档(长文本)的相似查询与询问

文章目录 1. 引言2. 简介3. 带关键字的查询方案4. 不带关键字的总结询问5. 实现代码 1. 引言 在调用ChatGPT接口时&#xff0c;我们常常受到4096个字符&#xff08;token&#xff09;的限制。这种限制对于处理长文本或者需要对文档进行相似查询和询问的场景来说是一个挑战。然…

如何复制投票链接投票怎样链接到公众号投票链接如何生成

关于微信投票&#xff0c;我们现在用的最多的就是小程序投票&#xff0c;今天的网络投票&#xff0c;在这里会教大家如何用“活动星投票”小程序来进行投票。 我们现在要以“妙趣拾光”为主题进行一次投票活动&#xff0c;我们可以在在微信小程序搜索&#xff0c;“活动星投票”…

【Python开发】FastAPI 03:请求参数—请求体

除了路径参数和查询参数&#xff0c;还有请求体&#xff0c;其用于传递 JSON、XML 或其他格式的数据&#xff0c;以便服务器能够读取并做出相应的处理&#xff0c;可以说请求体的作用更为强大。试想一下&#xff0c;如果存在七八个参数&#xff0c;路径参数和查询是不是就招架不…

Camera | 10.linux驱动 led架构-基于rk3568

前面文章我们简单给大家介绍了如何移植闪光灯芯片sgm3141&#xff0c;该驱动依赖了led子系统和v4l2子系统。 V4L2可以参考前面camera系列文章&#xff0c;本文主要讲述led子系统。 一、LED子系统框架 Linux内核的 led 子系统主要功能&#xff1a; 为每个设备在/sys/class/le…

《Linux内核源码分析》(2)进程原理及系统调用

《Linux内核源码分析》(2)进程原理及系统调用 一、进程 操作系统的作用&#xff1a;作为硬件的使用层&#xff0c;提供使用硬件资源的能力&#xff0c; 进程的作用&#xff1a;作为操作系统使用层&#xff0c;提供使用操作系统抽象出的资源层的能力 进程、线程和程序的区别&…

【计算机视觉】Segment Anything 安装配置及代码测试(含源代码)

文章目录 一、前言二、安装2.1 基本要求2.2 Install Segment Anything 三、代码使用示例3.1 Automatically generating object masks with SAM3.2 Environment Set-up3.3 显示标注3.4 图像示例3.5 Automatic mask generation3.6 Automatic mask generation options 一、前言 目…

客户体验:响应速度是他们的 No.1 Pick么?

服务响应速度在为消费者提供服务时极为重要&#xff0c;那么&#xff0c;在消费者整体体验中&#xff0c;响应速度是否是消费者最在意的呢&#xff1f; 无论是对企业还是消费者来说&#xff0c;时间都至关重要。消费者在寻求客户服务时&#xff0c;不喜欢等待。根据《客户服务受…