CoordinatorLayout + AppBarLayout + RecyclerView,滚动到最底部延迟的坑

本文主要是介绍CoordinatorLayout + AppBarLayout + RecyclerView,滚动到最底部延迟的坑,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

随着开发功能越来越复杂,我们使用的控件也越来越多。今天给大家带来一个找了好久解决掉的坑。

目前我们的APP首页使用了联动控件,CoordinatorLayout + AppBarLayout + RecyclerView。这个组合相信用过的都知道,坑其实挺多的,有造成屏幕抖动的,有造成部分白屏的,还有就是我解决的这个,快速滚动到底部,延迟很久才会回调RecyclerView的onScrollStateChanged。可能还有别的坑,目前就这几个。

先说一下原因吧,具体不知道是design的哪个版本升级,里面引入了惯性下滑的概念,滑动的速度越快,下滑的时间越长,就会让我们的界面实际上已经滑动到最底部了,但是还是卡在了下滑的过程之中,等惯性下滑的触发结束以后,才会触发RecyclerView的onScrollStateChanged。就会导致我们的RecyclerView明明已经滑动到最底部,需要去加载下一页数据,却一直卡着不动。

解决方法:其实明白了原因,网上关键字一搜解决方法还是很多的。主要是当碰到这个问题的时候,一直没有准确定位到原因。

分享一下我的调查和处理吧

1.我先是认为是应用的部分UI相关的处理比较复杂导致了应用的卡顿,然后将所有RecyclerView对于Ui相关的处理全部注释掉,发现没有任何改善。

2.分析是因为接口请求等太多太复杂,但是由于接口全部都是异步的,测试的时候心里预期80%不是这个引起的,注释完代码然后测试,结果正合我的预期。

3.由于RecyclerView中也实现了很多onScrollStateChanged 和onScroll 方法的重写,当时是怀疑自己写的onScroll 或者onScrollStateChanged方法内部处理导致了super的onScroll 和onScrollStateChanged 被拦截。同样注释代码测试,仍然不是。

4.最后看了一下所有代码都快注释完了,然后重新分析是不是布局导致的。然后看了这个联动控件,猜想可能是AppBarLayout 的滚动事件和RecyclerView的滚动事件相互冲突了。然后我把CoordinatorLayout注释了,运行,发现RecyclerView的回调正常了。然后有了上述问题原因的分析。最后成功解决了问题。

下面附上解决方法。自定义一个behavior类继承系统的AppBarLayout.Behavior ,加速结束惯性下滑的回调,当滑动到顶,或者滑动到底就认为滑动结束。下面附上代码。

public class ScrollAppBarLayoutBehavior extends AppBarLayout.Behavior {public ScrollAppBarLayoutBehavior() {super();}public ScrollAppBarLayoutBehavior(Context context, AttributeSet attrs) {super(context, attrs);}@Overridepublic void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,View target, int dx, int dy, int[] consumed, int type) {super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);stopNestedScrollIfNeeded(dy, child, target, type);}@Overridepublic void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target,int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed, type);stopNestedScrollIfNeeded(dyUnconsumed, child, target, type);}private void stopNestedScrollIfNeeded(int dy, AppBarLayout child, View target, int type) {if (type == ViewCompat.TYPE_NON_TOUCH) {final int currOffset = getTopAndBottomOffset();if ((dy < 0 && currOffset == 0) || (dy > 0 && currOffset == -child.getTotalScrollRange())) {ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH);}}}
}

重写的类写好以后,在xml里面AppBarLayout控件中使用我们自定义的ScrollAppBarLayoutBehavior即可。

<android.support.design.widget.AppBarLayoutandroid:id="@+id/appbar"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_behavior=".demo.ScrollAppBarLayoutBehavior" >

———————————————重要分割线———————————————————

补充一下.看到很多留言说,关于数据不够多或者空白的时候,上滑的时候,会导致大片空白问题.以及可能会滑动不回来的问题.

之前我这边没有复现,一直也比较忙,没时间帮忙看.最近在用的时候,正好也碰到了.把我这边的解决方案和大家共享一下.
一个个说.如果是空白界面,一般我们会使用统一的空白界面.由于显示着空白界面隐藏了recycleview,空白页面没有实现滑动功能,所以在整个头部滑动到最顶上的时候,很可能就滑不下来了.我这边做了最简单的处理.
直接增加了一个是否允许滑动的开关.
public void setEnable(boolean enable) {
        if (appbar == null) {
            return;
        }
        View mAppBarChildAt = appbar.getChildAt(0);
        AppBarLayout.LayoutParams mAppBarParams = (AppBarLayout.LayoutParams) mAppBarChildAt.getLayoutParams();
        if (enable) {
            mAppBarParams.setScrollFlags(AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL
                    | AppBarLayout.LayoutParams.SCROLL_FLAG_EXIT_UNTIL_COLLAPSED);
        } else {
            mAppBarParams.setScrollFlags(0);
        }
        mAppBarChildAt.setLayoutParams(mAppBarParams);
    }
此时可能会出现一个bug,这个appbar底部会有透明框.在xml 设置app:elevation="0dp" 就可以解决了.
同理,如果数据不够多的时候,可以理解为顶部折叠控件完全折叠,当然就只剩下底部的recycleview了.这个控件就是把顶部当成一个折叠控件.那么最好的解决方案,当然也是数据量少的时候,直接禁止上滑就好了.禁止滑动的逻辑就在上面.

这篇关于CoordinatorLayout + AppBarLayout + RecyclerView,滚动到最底部延迟的坑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/877461

相关文章

html 滚动条滚动过快会留下边框线的解决方案

《html滚动条滚动过快会留下边框线的解决方案》:本文主要介绍了html滚动条滚动过快会留下边框线的解决方案,解决方法很简单,详细内容请阅读本文,希望能对你有所帮助... 滚动条滚动过快时,会留下边框线但其实大部分时候是这样的,没有多出边框线的滚动条滚动过快时留下边框线的问题通常与滚动条样式和滚动行

golang实现延迟队列(delay queue)的两种实现

《golang实现延迟队列(delayqueue)的两种实现》本文主要介绍了golang实现延迟队列(delayqueue)的两种实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的... 目录1 延迟队列:邮件提醒、订单自动取消2 实现2.1 simplChina编程e简单版:go自带的time

uniapp小程序中实现无缝衔接滚动效果代码示例

《uniapp小程序中实现无缝衔接滚动效果代码示例》:本文主要介绍uniapp小程序中实现无缝衔接滚动效果的相关资料,该方法可以实现滚动内容中字的不同的颜色更改,并且可以根据需要进行艺术化更改和自... 组件滚动通知只能实现简单的滚动效果,不能实现滚动内容中的字进行不同颜色的更改,下面实现一个无缝衔接的滚动

Spring框架中@Lazy延迟加载原理和使用详解

《Spring框架中@Lazy延迟加载原理和使用详解》:本文主要介绍Spring框架中@Lazy延迟加载原理和使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录一、@Lazy延迟加载原理1.延迟加载原理1.1 @Lazy三种配置方法1.2 @Component

MySQL主从同步延迟问题的全面解决方案

《MySQL主从同步延迟问题的全面解决方案》MySQL主从同步延迟是分布式数据库系统中的常见问题,会导致从库读取到过期数据,影响业务一致性,下面我将深入分析延迟原因并提供多层次的解决方案,需要的朋友可... 目录一、同步延迟原因深度分析1.1 主从复制原理回顾1.2 延迟产生的关键环节二、实时监控与诊断方案

java实现延迟/超时/定时问题

《java实现延迟/超时/定时问题》:本文主要介绍java实现延迟/超时/定时问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java实现延迟/超时/定时java 每间隔5秒执行一次,一共执行5次然后结束scheduleAtFixedRate 和 schedu

Redis实现延迟任务的三种方法详解

《Redis实现延迟任务的三种方法详解》延迟任务(DelayedTask)是指在未来的某个时间点,执行相应的任务,本文为大家整理了三种常见的实现方法,感兴趣的小伙伴可以参考一下... 目录1.前言2.Redis如何实现延迟任务3.代码实现3.1. 过期键通知事件实现3.2. 使用ZSet实现延迟任务3.3

禁止HTML页面滚动的操作方法

《禁止HTML页面滚动的操作方法》:本文主要介绍了三种禁止HTML页面滚动的方法:通过CSS的overflow属性、使用JavaScript的滚动事件监听器以及使用CSS的position:fixed属性,每种方法都有其适用场景和优缺点,详细内容请阅读本文,希望能对你有所帮助... 在前端开发中,禁止htm

Redis延迟队列的实现示例

《Redis延迟队列的实现示例》Redis延迟队列是一种使用Redis实现的消息队列,本文主要介绍了Redis延迟队列的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录一、什么是 Redis 延迟队列二、实现原理三、Java 代码示例四、注意事项五、使用 Redi

MyBatis延迟加载的处理方案

《MyBatis延迟加载的处理方案》MyBatis支持延迟加载(LazyLoading),允许在需要数据时才从数据库加载,而不是在查询结果第一次返回时就立即加载所有数据,延迟加载的核心思想是,将关联对... 目录MyBATis如何处理延迟加载?延迟加载的原理1. 开启延迟加载2. 延迟加载的配置2.1 使用