RecyclerView实现无限数据循环效果:JFPicker的迭代思路

聊聊天

  很久没有写东西了,一方面是现在原生移动端开发的需求越来越少,再加上在小城市当程序猿,压力还是有一点的,所以最近一个多月都在看一些vue和css的教程,以前除了Android也做uniapp,所以还是学起来还是比较轻松的,这段时间的工作也开始做做网页前端,从app的开发思维转换为网页的开发思维确实有点不得劲,但真的还是挺有意思的。另一方面,也是最重要的,是我比较懒。
  JFPicker这个代码库,是我在上一家公司的时候做的,上一家公司是专门给企业的业务流程做开发的,所以会大量用到滚轮选择器,并且样式基本被美工固定了,所以封装被提上了日程。一开始我也用了github上的一些滚轮库,但很多地方都不满足客户的需求,比如滑动不够丝滑有卡顿、3D效果不明显等等,所以在AndroidPicker开源库的基础上,替换了核心的滚轮组件,使用了用RecyclerView实现的滚轮,以获得更丝滑的滚动体验和3D效果,另外也额外封装了ViewPager多次请求和普通的列表选择器。因为我只是个菜菜,所以我以为除了我和我的同事以外不会有人使用这个库,但偶尔会有一些小伙伴给我留言,有人使用还是蛮开心的,所以用摸鱼的时间迭代了一个版本,主要是增加了数据无限循环的功能。

实现过程

秉持着不要重复造轮子的原则,打开百度,搜索:RecyclerView实现无限数据循环,点开第一篇文章:Android无限循环RecyclerView的完美实现方案
在这篇文章里,提供了两种实现方式:

第一种实现方法:修改Adapter

  1. )在RecyclerView的Adapter中,重写getItemCount()方法返回Integer.MAX_VALUE。
  2. )重写onBindViewHolder()方法,对position参数取余运算,拿到position对应的真实数据索引
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    
    
    int index = position % dataList.size();
    holder.bind(dataList.get(index));
}

优点:实现比较简单
缺点:RecyclerView只能往下无限滑动,并不能往上无限滑动,参考文章也给出了解决方案,在初始化RecyclerView的时候,让其滑动到指定位置,如 Integer.MAX_VALUE/2,但仍有边界和滑动卡顿的问题

第二种实现方法:自定义LayoutManager

众所周知,RecyclerView.LayoutManager是RecyclerView中最重要的一个组件,负责以下任务:

  1. )定义子视图的位置和大小:LayoutManager决定RecyclerView中每个子视图的位置、大小和布局。通过调用LayoutManager中的方法,可以根据自己的需求自定义子视图的排列方式,如线性排列、网格排列、瀑布流排列等。
  2. )管理子视图的回收和复用:LayoutManager负责子视图的回收和复用,可以根据需要动态添加或移除子视图。这一特性可以大幅度减少内存的使用,提高应用程序的性能。
  3. )处理RecyclerView中的触摸和滚动事件:LayoutManager还可以处理RecyclerView中的触摸和滚动事件,使得RecyclerView可以响应用户的操作。

这些功能正是我们需求的,所以自定义LayoutManager是正道。

实现思路如下:
首先明确我们的需求:我们目的是做一个无限循环的滚轮控件,滚轮每一项高度固定,列表是n个滚轮项的高度,(也就是RecyclerView的列表项高度固定,RecyclerView的高度是n个列表项的高度)

  1. RecyclerView和其他的自定义ViewGroup一样,都会经过测量布局步骤,然后把列表项作为子View添加到RecyclerView中,滑动的话也是移动的子view的位置,我们完全可以通过Recycler.getChildAt()获取存活所有的列表项,然后根据每个列表项的getTop()和getBottom()方法判断这个列表项是否在屏幕内。
  2. 在onLayoutChildren方法中初始化布局,我们通过RecyclerView的高度和列表项的高度计算出RecyclerView可以填充几个列表项,然后填充列表项。
    onLayoutChildren是RecyclerView.LayoutManager类的一个方法,用于测量和布置RecyclerView中的项目。它通常在以下情况下被调用:
    1.) 当RecyclerView首次设置LayoutManager时:在设置LayoutManager时, RecyclerView会调用onLayoutChildren以获取初始布局。
    2.) 当RecyclerView的数据集发生更改时:当RecyclerView的数据集更改(例如添加、删除或移动项目)时,RecyclerView会调用onLayoutChildren来重新布局所有项目。
    3.) 当RecyclerView的尺寸发生更改时:当RecyclerView的尺寸更改时(例如,用户更改了屏幕方向或调整了RecyclerView的大小),RecyclerView会调用onLayoutChildren来重新布局所有项目。
    在这些情况下,onLayoutChildren方法都会被调用以确保RecyclerView中的项目能够正确地显示和布局。
  3. 当用户手动滑动或者 调用RecyclerView的scrollXXX()方法时,LayoutManager的scrollVerticallyBy方法会被调用,我们可以获取到需要滑动的距离,通过第一个列表项的getTop()和最后一个列表项的getBottom()判断是否滑动到头或者滑动到底,如果是就创建新的子view并添加到RecyclerView(如果向上滑动就按数据源倒叙添加列表项,如果向下滑动就按数据源正序添加列表项),这样就能实现无限滑动。当然,滑动出屏幕的子view肯定需要被回收和移除。
  4. 关于创建列表项:我们肯定要通过RecyclerView.getViewForPosition(i)方法创建,该方法最后是调用Adapter.onCreateViewHolder()方法创建,这样我们就可以创建多个adapterPosition 相同的列表项,并且也能通过RecyclerView.getPosition(@NonNull View view)方法获取正确的adapterPosition

原文章的几个问题:

  1. 原文每次只添加一个列表项,当用户滑动的非常快的时候(或者我们通过scrollxxx方法滑动时),会发生这种情况:一次的滑动距离比一个列表项的高度要大,这样就会出现无意义的空白,所以我们要判断一次的滑动距离是否比一个列表项的高度大,如果是,我们需要按照滑动方向正序或倒叙添加多个列表项
  2. 原文没有提供滑动到指定位置列表项的方法,因为我们做的是滚轮组件,所以这个是必须的,解决方法也很简单:先获取屏幕内的所有可见列表项,然后获取正中间的列表项,通过getPosition()方法获取该列表项的adapterPosition,对比要滑动到的位置,向上或向下滑动差值个数的列表项距离即可。

我们按照实现思路和解决问题的方法,修改原文章中的代码,就可以很轻松的实现我们想要的效果,因为比较简单,所以这里不再贴出代码,有需要的可以去github查看:VerticalLooperLayoutManager 无限数据循环的LayoutManager
最终看一下实现的效果:

数据无限循环的RecyclerView

猜你喜欢

转载自blog.csdn.net/weixin_43864176/article/details/129564627