iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >RecyclerView无限循环效果怎么实现
  • 406
分享到

RecyclerView无限循环效果怎么实现

2023-07-05 18:07:19 406人浏览 泡泡鱼
摘要

这篇文章主要介绍“RecyclerView无限循环效果怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“RecyclerView无限循环效果怎么实现”文章能帮助大家解决问题。1、修改adpter

这篇文章主要介绍“RecyclerView无限循环效果怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“RecyclerView无限循环效果怎么实现”文章能帮助大家解决问题。

    1、修改adpter和数据映射实现

    Google了一下,有关recyclerView无限循环的博客很多,内容基本一模一样。大部分的博客都提到/使用了一种修改adpter以及数据映射的方式,主要有以下几步:

    1. 修改adapter的getItemCount()方法,让其返回Integer.MAX_VALUE

    2. 在取item的数据时,使用索引position % list.size

    3. 初始化的时候,让recyclerView滑到近似Integer.MAX_VALUE/2的位置,避免用户滑到边界。

    在逛stackOverFlow时找到了这种方案的出处: java - How to cycle through items in Android RecyclerView? - Stack Overflow

    这个方法是建立了一个数据和位置的映射关系,因为itemCount无限大,所以用户可以一直滑下去,又因对位置与数据的取余操作,就可以在每经历一个数据的循环后重新开始。看上去RecyclerView就是无限循环的。

    很多博客会说这种方法并不好,例如对索引进行了计算/用户可能会滑到边界导致需要再次动态调整到中间之类的。然后自己写了一份自定义layoutManager后觉得用自定义layoutManager的方法更好。

    其实我倒不这么觉得。

    事实上,这种方法已经可以很好地满足大部分无限循环的场景,并且由于它依然沿用了LinearLayoutManager。就代表列表依旧可以使用LLM(LinearLayoutManager)封装好的布局和缓存机制。

    • 首先索引计算这个谈不上是个问题。至于用户滑到边界的情况,也可以做特殊处理调整位置。(另外真的有人会滑约Integer.MAX_VALUE/2大约1073741823个position吗?

    • 性能上也无需担心。从数字的直觉上,设置这么多item然后初始化scrollToPosition(Integer.MAX_VALUE/2)看上去好像很可怕,性能上可能有问题,会卡顿巴拉巴拉。

    实际从初始化到scrollPosition到真正onlayoutChildren系列操作,主要经过了以下几步。

    • 设置mPendingScrollPosition,确定要滑动的位置,然后requestLayout()请求布局;

    @Overridepublic void scrollToPosition(int position) {    mPendingScrollPosition = position;//更新position    mPendingScrollPositionOffset = INVALID_OFFSET;     if (mPendingSavedState != null) {        mPendingSavedState.invalidateAnchor();    }    requestLayout();}
    • 请求布局后会触发recyclerView的dispatchLayout,最终会调用onLayoutChildren进行子View的layout,如官方注释里描述的那样,onLayoutChildren最主要的工作是:确定锚点、layoutState,调用fill填充布局。

    onLayoutChildren部分源码

    @Overridepublic void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {    // layout algorithm:    // 1) by checking children and other variables, find an anchor coordinate and an anchor    //  item position.    // 2) fill towards start, stacking from bottom    // 3) fill towards end, stacking from top    // 4) scroll to fulfill requirements like stack from bottom.    //..............    // 省略,前面主要做了一些异常状态的检测、针对焦点的特殊处理、确定锚点对anchorInfo赋值、偏移量计算    int startOffset;    int endOffset;    final int firstLayoutDirection;    if (mAnchorInfo.mLayoutFromEnd) {        // fill towards start        updateLayoutStateToFillStart(mAnchorInfo); //根据mAnchorInfo更新layoutState        mLayoutState.mExtraFillSpace = extraForStart;        fill(recycler, mLayoutState, state, false);//填充        startOffset = mLayoutState.mOffset;        final int firstElement = mLayoutState.mCurrentPosition;        if (mLayoutState.mAvailable > 0) {            extraForEnd += mLayoutState.mAvailable;        }        // fill towards end        updateLayoutStateToFillEnd(mAnchorInfo);//更新layoutState为fill做准备        mLayoutState.mExtraFillSpace = extraForEnd;        mLayoutState.mCurrentPosition += mLayoutState.mItemDirection;        fill(recycler, mLayoutState, state, false);//填充        endOffset = mLayoutState.mOffset;        if (mLayoutState.mAvailable > 0) {            // end could not consume all. add more items towards start            extraForStart = mLayoutState.mAvailable;            updateLayoutStateToFillStart(firstElement, startOffset);//更新layoutState为fill做准备            mLayoutState.mExtraFillSpace = extraForStart;            fill(recycler, mLayoutState, state, false);            startOffset = mLayoutState.mOffset;        }    } else {        //layoutFromStart 同理,省略    }    //try to fix gap , 省略
    • onLayoutChildren中会调用updateAnchorInfoForLayout更新anchoInfo锚点信息,updateLayoutStateToFillStart/End再根据anchorInfo更新layoutState为fill填充做准备。

    • fill的源码: `

    int fill(RecyclerView.Recycler recycler, LayoutState layoutState,        RecyclerView.State state, boolean stopOnFocusable) {    // max offset we should set is mFastScroll + available    final int start = layoutState.mAvailable;    if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {        // TODO ugly bug fix. should not happen        if (layoutState.mAvailable < 0) {            layoutState.mScrollingOffset += layoutState.mAvailable;        }        recycleByLayoutState(recycler, layoutState);    }    int remainingSpace = layoutState.mAvailable + layoutState.mExtraFillSpace;    LayoutChunkResult layoutChunkResult = mLayoutChunkResult;    // (不限制layout个数/还有剩余空间) 并且 有剩余数据    while ((layoutState.mInfinite || remainingSpace > 0) && layoutState.hasMore(state)) {        layoutChunkResult.resetInternal();        if (RecyclerView.VERBOSE_TRACING) {            TraceCompat.beginSection("LLM LayoutChunk");        }        layoutChunk(recycler, state, layoutState, layoutChunkResult);        if (RecyclerView.VERBOSE_TRACING) {            TraceCompat.endSection();        }        if (layoutChunkResult.mFinished) {            break;        }        layoutState.mOffset += layoutChunkResult.mConsumed * layoutState.mLayoutDirection;                if (!layoutChunkResult.mIgnoreConsumed || layoutState.mScrapList != null                || !state.isPreLayout()) {            layoutState.mAvailable -= layoutChunkResult.mConsumed;            // we keep a separate remaining space because mAvailable is important for recycling            remainingSpace -= layoutChunkResult.mConsumed;        }        if (layoutState.mScrollingOffset != LayoutState.SCROLLING_OFFSET_NaN) {            layoutState.mScrollingOffset += layoutChunkResult.mConsumed;            if (layoutState.mAvailable < 0) {                layoutState.mScrollingOffset += layoutState.mAvailable;            }            recycleByLayoutState(recycler, layoutState);//回收子view        }        if (stopOnFocusable && layoutChunkResult.mFocusable) {            break;        }    }    if (DEBUG) {        validateChildOrder();    }    return start - layoutState.mAvailable;

    fill主要干了两件事:

    • 循环调用layoutChunk布局子view并计算可用空间

    • 回收那些不在屏幕上的view

    所以可以清晰地看到LLM是按需layout、回收子view。

    就算创建一个无限大的数据集,再进行滑动,它也是如此。可以写一个修改adapter和数据映射来实现无限循环的例子,验证一下我们的猜测:

    //adapter关键代码@NonNull@Overridepublic DemoViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {    LayoutInflater inflater = LayoutInflater.from(parent.getContext());    Log.d("DemoAdapter","onCreateViewHolder");    return new DemoViewHolder(inflater.inflate(R.layout.item_demo, parent, false));}@Overridepublic void onBindViewHolder(@NonNull DemoViewHolder holder, int position) {    Log.d("DemoAdapter","onBindViewHolder: position"+position);    String text = mData.get(position % mData.size());    holder.bind(text);}@Overridepublic int getItemCount() {    return Integer.MAX_VALUE;}

    在代码我们里打印了onCreateViewHolder、onBindViewHolder的情况。我们只要观察这viewHolder的情况,就知道进入界面再滑到Integer.MAX_VALUE/2时会初始化多少item。 `

    RecyclerView recyclerView = findViewById(R.id.rv);recyclerView.setAdapter(new DemoAdapter());LinearLayoutManager layoutManager =  new LinearLayoutManager(this);layoutManager.setOrientation(RecyclerView.VERTICAL);recyclerView.setLayoutManager(layoutManager);recyclerView.scrollToPosition(Integer.MAX_VALUE/2);

    日志打印:

    RecyclerView无限循环效果怎么实现

    可以看到,页面上共有5个item可见,LLM也按需创建、layout了5个item。

    2、自定义layoutManager

    找了找网上自定义layoutManager去实现列表循环的博客和代码,拷贝和复制的很多,找不到源头是哪一篇,这里就不贴链接了。大家都是先说第一种修改adapter的方式不好,然后甩了一份自定义layoutManager的代码。

    然而自定义layoutManager难点和坑都很多,很容易不小心就踩到,一些博客的代码也有类似问题。 基本的一些坑点在张旭童大佬的博客中有提及, 【Android】掌握自定义LayoutManager

    比较常见的问题是:

    • 不计算可用空间和子view消费的空间,layout出所有的子view。相当于抛弃了子view的复用机制

    • 没有合理利用recyclerView的回收机制

    • 没有支持一些常用但比较重要的api的实现,如前面提到的scrollToPosition。

    其实最理想的办法是继承LinearLayoutManager然后修改,但由于LinearLayoutManager内部封装的原因,不方便像GridLayoutManager那样去继承LinearLayoutManager然后进行扩展(主要是包外的子类会拿不到layoutState等)。

    要实现一个线性布局的layoutManager,最重要的就是实现一个类似LLM的fill(前面有提到过源码,可以翻回去看看)和layoutChunk方法。

    (当然,可以照着LLM写一个丐版,本文就是这么做的。)

    fill方法很重要,就如同官方注释里所说的,它是一个magic func。

    从OnLayoutChildren到触发scroll滑动,都是调用fill来实现布局。

    int fill(RecyclerView.Recycler recycler, LayoutState layoutState,        RecyclerView.State state, boolean stopOnFocusable) {

    前面提到过fill主要干了两件事:

    • 循环调用layoutChunk布局子view并计算可用空间

    • 回收那些不在屏幕上的view

    而负责子view布局的layoutChunk则和把一个大象放进冰箱一样,主要分三步走:

    • add子view

    • measure

    • layout 并计算消费了多少空间

    就像下面这样:

    private void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,                         LayoutState layoutState, LayoutChunkResult result) {    View view = layoutState.next(recycler, state);    if (view == null) {        result.mFinished = true;        return;    }    RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();    // add    if (layoutState.mLayoutDirection != LayoutState.LAYOUT_START) {        addView(view);    } else {        addView(view, 0);    }    Rect insets = new Rect();    calculateItemDecorationsForChild(view, insets);    // 测量    measureChildWithMargins(view, 0, 0);    //布局    layoutChild(view, result, params, layoutState, state);    // Consume the available space if the view is not removed OR changed    if (params.isItemRemoved() || params.isItemChanged()) {        result.mIgnoreConsumed = true;    }    result.mFocusable = view.hasFocusable();}

    那最关键的如何实现循环呢??

    其实和修改adapter的实现方法有异曲同工之妙,本质都是修改位置与数据的映射关系。

    修改layoutStae的方法:

        boolean hasMore(RecyclerView.State state) {        return Math.abs(mCurrentPosition) <= state.getItemCount();    }    View next(RecyclerView.Recycler recycler, RecyclerView.State state) {        int itemCount = state.getItemCount();        mCurrentPosition = mCurrentPosition % itemCount;        if (mCurrentPosition < 0) {            mCurrentPosition += itemCount;        }        final View view = recycler.getViewForPosition(mCurrentPosition);        mCurrentPosition += mItemDirection;        return view;    }}

    关于“RecyclerView无限循环效果怎么实现”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识,可以关注编程网精选频道,小编每天都会为大家更新不同的知识点。

    --结束END--

    本文标题: RecyclerView无限循环效果怎么实现

    本文链接: https://www.lsjlt.com/news/354257.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

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

    下载Word文档
    猜你喜欢
    • RecyclerView无限循环效果怎么实现
      这篇文章主要介绍“RecyclerView无限循环效果怎么实现”的相关知识,小编通过实际案例向大家展示操作过程,操作方法简单快捷,实用性强,希望这篇“RecyclerView无限循环效果怎么实现”文章能帮助大家解决问题。1、修改adpter...
      99+
      2023-07-05
    • Unity ScrollView实现无限循环效果
      本文实例为大家分享了Unity ScrollView实现无限循环效果的具体代码,供大家参考,具体内容如下 在Unity引擎中ScrollView组件是一个使用率比较高的组件,该组件能...
      99+
      2022-11-12
    • Android ViewPager实现无限循环效果
      最近项目里有用到ViewPager来做广告运营位展示,看到现在很多APP的广告运营位都是无限循环的,所以就研究了一下这个功能的实现。 先看看效果 从一个方向上一直滑动,么有...
      99+
      2022-06-06
      循环 viewpager Android
    • js怎么实现无限循环轮播图效果
      小编给大家分享一下js怎么实现无限循环轮播图效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!知识要点1.实现无限循环的原理:以...
      99+
      2022-10-19
    • CSS3怎么实现无限循环的无缝滚动效果
      这篇文章主要讲解了“CSS3怎么实现无限循环的无缝滚动效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS3怎么实现无限循环的无缝滚动效果”吧!1. 使用CSS3来实现若要用CSS3的属...
      99+
      2023-07-05
    • 怎么实现Android TV 3D卡片无限循环效果
      这篇文章主要讲解了“怎么实现Android TV 3D卡片无限循环效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“怎么实现Android TV 3D卡片无限循环效果”吧!##思路自定义Vi...
      99+
      2023-06-25
    • Android实现轮播图无限循环效果
      本文实例为大家分享了Android轮播图无限循环的具体代码,供大家参考,具体内容如下 实现无限循环 在getCount()方法中,返回一个很大的值,Integer.MAX_VA...
      99+
      2022-06-06
      轮播图 循环 轮播 Android
    • Unity ScrollView如何实现无限循环效果
      小编给大家分享一下Unity ScrollView如何实现无限循环效果,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!具体内容如下在Unity引擎中ScrollVi...
      99+
      2023-06-20
    • Android ViewPager怎么去实现无限循环滚动回绕效果
      不懂Android ViewPager怎么去实现无限循环滚动回绕效果?其实想解决这个问题也不难,下面让小编带着大家一起学习怎么去解决,希望大家阅读完这篇文章后大所收获。android系统提供的ViewPager标准方式是左右可以自由滑动,但...
      99+
      2023-05-30
      android viewpager 滚动效果
    • CSS3如何实现无限循环的滚动效果
      这篇文章主要讲解了“CSS3如何实现无限循环的滚动效果”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“CSS3如何实现无限循环的滚动效果”吧!1. 使用CSS3来实现若要用CSS3的属性实现的...
      99+
      2023-07-04
    • Scala无限循环怎么实现
      本篇内容主要讲解“Scala无限循环怎么实现”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Scala无限循环怎么实现”吧!有的时候,我们可能需要多次执行同一块代码。一般情况下,语句是按顺序执行的...
      99+
      2023-06-19
    • C#怎么实现无限循环
      本篇内容主要讲解“C#怎么实现无限循环”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“C#怎么实现无限循环”吧!循环控制语句循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建...
      99+
      2023-06-17
    • Android ViewPager导航小圆点实现无限循环效果
      之前用View Pager做了一个图片切换的推荐栏(就类似与淘宝、头条客户端顶端的推荐信息栏),利用View Pager很快就能实现,但是一次无意间使用淘宝APP的时候,突然发现它的效果和我做的还不一样,淘宝APP的推荐栏可以左右无限循环切...
      99+
      2023-05-30
      viewpager 导航 无限循环
    • Android TV 3D卡片无限循环效果
      TV 3D卡片无限循环效果,供大家参考,具体内容如下 ##前言 1、需求:实现3个卡片实现无限循环效果:1-2-3-1-2-3-1…,而且要实现3D效果:中间突出,两侧呈角度显示 2...
      99+
      2022-11-12
    • 如何使用CSS3实现无限循环的无缝滚动效果
      这篇文章将为大家详细讲解有关如何使用CSS3实现无限循环的无缝滚动效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。1. 使用CSS3来实现若要用CSS3的属性实现的话,...
      99+
      2022-10-19
    • Android实现带指示点的自动轮播无限循环效果
      想要实现无限轮播,一直向左滑动,当到最后一个view时,会滑动到第一个,无限… 可以自己写ViewPager然后加handler先实现自动滚动,当然这里我为了项目的进度直接使用...
      99+
      2022-06-06
      自动 循环 轮播 Android
    • Android实现横向无限循环滚动的单行弹幕效果
      本期将带领大家实现一个这样的效果,支持无限循环的单行弹幕效果。 实现思路分析 要实现上面的效果,我们先拆分下实现要素: 1、弹幕布局是从屏幕的右侧向左侧滚动,单个弹幕之间的间距是固...
      99+
      2022-11-12
    • Android ViewPager如何实现无限循环轮播广告位Banner效果
      这篇文章将为大家详细讲解有关Android ViewPager如何实现无限循环轮播广告位Banner效果,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。现在一些app通常会在头部放一个广告位,底部放置一行小...
      99+
      2023-05-30
      android viewpager banner
    • 使用CSS怎么实现背景无缝无限循环
      本篇文章给大家分享的是有关使用CSS怎么实现背景无缝无限循环,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。HTML<div class="dog&qu...
      99+
      2023-06-08
    • Android如何实现通知消息水平播放、无限循环效果
      小编给大家分享一下Android如何实现通知消息水平播放、无限循环效果,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!先看效果图:这个效果也很常见,实现的方法也有很多,我是使用RecyclerView来实现的,觉得还是挺不错...
      99+
      2023-05-30
      android
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作