我的编程空间,编程开发者的网络收藏夹
学习永远不晚

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

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

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

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

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

<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.AutoLoopViewPagerandroid:id="@+id/looper_pager"android:layout_width="match_parent"android:layout_height="match_parent"AutoLoopStyle:duration="4000"android:overScrollMode="never" />                        <LinearLayoutandroid: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的情况下才能正常使用。不过也是一种解决问题的思路

来源地址:https://blog.csdn.net/ChenYiRan123456/article/details/130973175

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

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

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Android listview的滑动冲突解决方法

Android listview的滑动冲突解决方法 在Android开发的过程中,有时候会遇到子控件和父控件都要滑动的情况,尤其是当子控件为listview的时候。就比如在一个ScrollView里有一个listview,这种情况较常见,就
2022-06-06

Android滑动冲突问题的解决方法

叙述滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。 关于滑动冲突滑动冲突分类 滑动冲突,总的来说就是两类。 1、同方向滑
2022-06-06

Android使用NestedScrollView内嵌RecycleView滑动冲突问题如何解决

这篇“Android使用NestedScrollView内嵌RecycleView滑动冲突问题如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,
2023-07-02

Android滑动事件冲突的解决方法

滑动是Android中不可缺少的一部分,多个滑动必然会产生冲突,比如我们最常见的是ScrollView中嵌套了ListView,一般做法是计算出ListView的总高度,这样就不用去滑动ListView了。又比如一个ViewPager嵌套F
2022-06-06

Android中DrawerLayout+ViewPager滑动冲突的解决方法

DrawerLayout 是 Android 官方的侧滑菜单控件,而 ViewPager 相信大家都很熟悉了。今天这里就讲一下当在 DrawerLayout 中嵌套 ViewPager 时,要如何解决滑动冲突的问题,效果如下:首先,让我们先
2023-05-31

Android 中SwipeRefreshLayout与ViewPager滑动事件冲突解决方法

Android 中SwipeRefreshLayout与ViewPager滑动事件冲突解决方法 问题描述:开发中发现,SwipeRefreshLayout的下拉刷新,与ViewPager开发的banner的左右滑动事件有一点冲突,导致ban
2022-06-06

浅谈Android View滑动冲突的解决方法

引言 这一篇文章我们就通过介绍滑动冲突的规则和一个实例来更加深入的学习View的事件分发机制。 1、外部滑动方向和内部滑动方向不一致 考虑这样一种场景,开发中我们经常使用ViewPager和Fragment配合使用所组成的页面滑动效果,很多
2022-06-06

Android中RecyclerView嵌套滑动冲突解决的代码片段

在纵向RecyclerView嵌套横向RecyclerView时,如果纵向RecyclerView有下拉刷新功能,那么内部的横向RecyclerView的横向滑动体验会很差.(只有纯横向滑动时,才能滑动内部的横向RecyclerView,否
2022-06-06

android多种滑动冲突的解决方案

一、前言 Android 中解决滑动的方案有2种:外部拦截法 和内部拦截法。 滑动冲突也存在2种场景: 横竖滑动冲突、同向滑动冲突。 所以我就写了4个例子来学习如何解决滑动冲突的,这四个例子分别为: 外部拦截法解决横竖冲突、外部拦截法解决同
2022-06-06

android中view手势滑动冲突的解决方法

Android手势事件的冲突跟点击事件的分发过程息息相关,由三个重要的方法来共同完成,分别是:dispatchTouchEvent、onInterceptTouchEvent和onTouchEvent。public boolean disp
2022-06-06

Android滑动冲突的完美解决方案

关于滑动冲突 在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂的页面,特别是为了兼容小屏手机而使用了ScrollView以后,就会出现很多点击事件的冲突,最经典的就是ScrollView中嵌套了ListView
2022-06-06

Android滑动冲突的完美解决

Android滑动在智能手机上是必备的操作,但是在开发的时候,你是否和我一样,经常会遇到滑动冲突的问题,比如最简单需要在ListView里面添加一个侧滑动作,这时候冲突时必然的,那我们该如何解决这个问题呢? 先来说一下滑动冲突都有那些,该
2022-06-06

Android下拉刷新与轮播图滑动冲突解决方案

最近在开发中遇到了这样一个问题,在下拉刷新组件中包含了一个轮播图组件,当左右滑动的图片时很容易触发下拉刷新,如下图所示:如图中红色箭头所示方向切换轮播图,很容易触发下拉刷新。网上查了很多方法,发现都不能很好的解决,于是自己研究了下。 我选用
2022-06-06

android基础教程之android的listview与edittext冲突解决方法

最近遇到一个关于android软键盘的问题。在ListView中每个Item中都有个EditText,在最后的几个Item中,EditText第一次点击界面还能向上弹出,正常显示, 但第二次点击时,软件盘就把最后的几个Item给正当住了。这
2022-06-06

浅谈Android实践之ScrollView中滑动冲突处理解决方案

1. 前言 在Android开发中,如果是一些简单的布局,都很容易搞定,但是一旦涉及到复杂的页面,特别是为了兼容小屏手机而使用了ScrollView以后,就会出现很多点击事件的冲突,最经典的就是ScrollView中嵌套了ListView
2022-06-06

Android App中ViewPager所带来的滑动冲突问题解决方法

叙述 滑动冲突可以说是日常开发中比较常见的一类问题,也是比较让人头疼的一类问题,尤其是在使用第三方框架的时候,两个原本完美的控件,组合在一起之后,忽然发现整个世界都不好了。 关于滑动冲突 滑动冲突分类: 滑动冲突,总的来说就是两类。 1.同
2022-06-06

Android应用中的View出现滑动冲突如何解决

本篇文章给大家分享的是有关Android应用中的View出现滑动冲突如何解决,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。1、外部滑动方向和内部滑动方向不一致考虑这样一种场景,
2023-05-31

编程热搜

  • Android:VolumeShaper
    VolumeShaper(支持版本改一下,minsdkversion:26,android8.0(api26)进一步学习对声音的编辑,可以让音频的声音有变化的播放 VolumeShaper.Configuration的三个参数 durati
    Android:VolumeShaper
  • Android崩溃异常捕获方法
    开发中最让人头疼的是应用突然爆炸,然后跳回到桌面。而且我们常常不知道这种状况会何时出现,在应用调试阶段还好,还可以通过调试工具的日志查看错误出现在哪里。但平时使用的时候给你闹崩溃,那你就欲哭无泪了。 那么今天主要讲一下如何去捕捉系统出现的U
    Android崩溃异常捕获方法
  • android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
    系统的设置–>电池–>使用情况中,统计的能耗的使用情况也是以power_profile.xml的value作为基础参数的1、我的手机中power_profile.xml的内容: HTC t328w代码如下:
    android开发教程之获取power_profile.xml文件的方法(android运行时能耗值)
  • Android SQLite数据库基本操作方法
    程序的最主要的功能在于对数据进行操作,通过对数据进行操作来实现某个功能。而数据库就是很重要的一个方面的,Android中内置了小巧轻便,功能却很强的一个数据库–SQLite数据库。那么就来看一下在Android程序中怎么去操作SQLite数
    Android SQLite数据库基本操作方法
  • ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
    工作的时候为了方便直接打开编辑文件,一些常用的软件或者文件我们会放在桌面,但是在ubuntu20.04下直接直接拖拽文件到桌面根本没有效果,在进入桌面后发现软件列表中的软件只能收藏到面板,无法复制到桌面使用,不知道为什么会这样,似乎并不是很
    ubuntu21.04怎么创建桌面快捷图标?ubuntu软件放到桌面的技巧
  • android获取当前手机号示例程序
    代码如下: public String getLocalNumber() { TelephonyManager tManager =
    android获取当前手机号示例程序
  • Android音视频开发(三)TextureView
    简介 TextureView与SurfaceView类似,可用于显示视频或OpenGL场景。 与SurfaceView的区别 SurfaceView不能使用变换和缩放等操作,不能叠加(Overlay)两个SurfaceView。 Textu
    Android音视频开发(三)TextureView
  • android获取屏幕高度和宽度的实现方法
    本文实例讲述了android获取屏幕高度和宽度的实现方法。分享给大家供大家参考。具体分析如下: 我们需要获取Android手机或Pad的屏幕的物理尺寸,以便于界面的设计或是其他功能的实现。下面就介绍讲一讲如何获取屏幕的物理尺寸 下面的代码即
    android获取屏幕高度和宽度的实现方法
  • Android自定义popupwindow实例代码
    先来看看效果图:一、布局
  • Android第一次实验
    一、实验原理 1.1实验目标 编程实现用户名与密码的存储与调用。 1.2实验要求 设计用户登录界面、登录成功界面、用户注册界面,用户注册时,将其用户名、密码保存到SharedPreference中,登录时输入用户名、密码,读取SharedP
    Android第一次实验

目录