【问题标题】:How to make RecyclerView scroll smoothly?如何让 RecyclerView 平滑滚动?
【发布时间】:2015-09-23 19:13:13
【问题描述】:

这更像是一个通用问题,但经过大量搜索和尝试后,我无法理解为什么这很难实现。 This 是我能找到但仍然无法实施的最接近的答案。

具体来说,我将 RecyclerView 与 GridLayoutManager 一起使用。我想要的只是平滑滚动的网格布局(如默认的画廊应用程序),没什么花哨的,但网格布局管理器的默认实现以“生涩”的方式滚动视图。我尝试实现上述链接中的方法,但没有成功。

我也尝试实现 LinearSmoothScroller 但我不确定如何实现 computeScrollVectorForPosition 方法。 computeScrollVectorForPosition 上的Google's documentation 字面上有0 个单词。

我找到了this 3 part tutorial,但帮助甚微。所以,我想问的是:是否有某种模板代码可以在 LinearSmoothScroller 中实现,或者通过扩展 RecyclerView.SmoothScroller 来实现平滑滚动?即使代码取决于网格布局中每行的项目数和项目数,也必须有一些方法可以轻松完成。我在这里错过了什么吗?

【问题讨论】:

  • “我在这里遗漏了什么吗?” -- 或许您应该使用 Traceview、StrictMode 等工具来确定您现有代码为何“生涩”。
  • @commonsWare 所以你的意思是 GridLayoutManager 的默认实现应该平滑地滚动 gridview ?对不起,如果我听起来很菜鸟,我对 Android 编程很陌生。
  • "所以你的意思是 GridLayoutManager 的默认实现应该平滑地滚动 gridview ?" ——是的,至少对于我对“顺利”的定义。 Android 中“生涩”滚动的典型来源是应用程序在主应用程序线程更新 UI 上花费了太多时间。对于RecyclerView,这意味着在onBindViewHolder()onCreateViewHolder() 中花费太多时间。这些每个都需要在亚毫秒时间内返回,这意味着您不能在其中执行磁盘 I/O 或网络 I/O。
  • @CommonsWare 谢谢你的回答,我想我找到了问题所在。我在 onBindViewHolder() 上使用holder.photo.setImageBitmap(BitmapFactory.decodeFile(itemList.get(position).getAbsolutePath()));,每个图像文件大约 100kb,列表中有十几个图像。我会尝试更好地实现它。

标签: android android-recyclerview smooth-scrolling gridlayoutmanager


【解决方案1】:

ActivityFragment 中声明 RecyclerView 的任何位置添加此内容

RecyclerView mRecyclerview = (RecyclerView) findViewById(...);
mRecyclerview.setNestedScrollingEnabled(false);

setNestedScrollview(false) 为您完成工作。

【讨论】:

    【解决方案2】:

    Android 中“生涩”滚动的典型原因是应用程序在主应用程序线程更新 UI 上花费了太多时间。对于RecyclerView,这意味着在onBindViewHolder()onCreateViewHolder() 中花费太多时间。这些每个都需要在亚毫秒时间内返回,这意味着您不能在其中执行磁盘 I/O 或网络 I/O。

    认为我找到了问题所在。我正在使用 holder.photo.setImageBitmap(BitmapFactory.decodeFile(itemList.get(position).get‌​AbsolutePath()));在 onBindViewHolder() 上,每个图像文件大约 100kb,列表中有大约十几个图像

    是的,这将在主应用程序线程上执行磁盘 I/O 和图像解码。这将慢到足以导致 UI 卡顿(即“生涩”滚动)。

    考虑使用图像加载库,例如 Picasso 或 Universal Image Loader,因为它们可以从位图中异步填充您的 ImageView

    This sample app 使用 Universal Image Loader 来帮助填充 RecyclerView(使用 GridLayoutManager)的内容,数据源是设备上的可用视频。

    【讨论】:

    • 谢谢,我会检查并实施。同时,使用this 简单的解决方案而不是使用单独的库怎么样?
    • @rockfight:因为这与您的问题无关。该页面的重点是内存效率,而不是主应用程序线程时间。
    • UIL 在图像驻留在 sd 卡中时不起作用(文件路径以 /storage 开头。我为此使用了 Glide,它为我的问题提供了一个完美的解决方案
    • 这对我有用。我在图像大尺寸时面临同样的问题。当我们使用BitmapImageView 中设置图像时,它就像@CommonsWare 答案一样工作。
    • @CommonsWare,在我的应用程序中,recyclerview 滚动不流畅,因为我在 onBindViewHolder 内膨胀视图,有没有其他方法可以添加没有布局膨胀器的视图。
    【解决方案3】:

    我刚遇到这个问题,禁用嵌套滚动修复了它。 这样做:

    yourRecyclerview.setNestedScrollingEnabled(false);
    

    或者您可以更改定义 RecyclerView 的 xml 文件中的值:

    <android.support.v7.widget.RecyclerView
        android:id="@+id/yourRecyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:nestedScrollingEnabled="false"/>
    

    【讨论】:

    • 感谢@Arman,我在 NestedScrollView 中使用了 RecyclerView,之后我得到了这个。但现在它工作正常。
    【解决方案4】:

    我刚遇到这个问题,我得到了 我将RecyclerView 放入ScrollView 所以请永远不要把RecyclerView放在ScrollView里面,这也可能导致。

    mLayoutManager.findFirstVisibleItemPosition()
    

    那总是返回一个固定值。并检查

    recyclerview.setNestedScrollingEnabled(false);
    

    【讨论】:

      【解决方案5】:

      我通过覆盖calculateSpeedPerPixel(DisplayMetrics displayMetrics) 方法使滚动变得平滑:

      public class CustomLayoutManager extends LinearLayoutManager {
      
          protected CenterLayoutManager(Context context, int orientation, boolean reverseLayout) {
              super(context, orientation, reverseLayout);
          }
      
          @Override
          public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
              RecyclerView.SmoothScroller smoothScroller = new CenterSmoothScroller(recyclerView.getContext());
              smoothScroller.setTargetPosition(position);
              startSmoothScroll(smoothScroller);
          }
      
          private class CenterSmoothScroller extends LinearSmoothScroller {
      
              CenterSmoothScroller(Context context) {
                  super(context);
              }
      
              @Override
              public int calculateDtToFit(int viewStart, int viewEnd, int boxStart, int boxEnd, int snapPreference) {
                  return (boxStart + (boxEnd - boxStart) / 2) - (viewStart + (viewEnd - viewStart) / 2);
              }
      
              @Override
              protected float calculateSpeedPerPixel(DisplayMetrics displayMetrics) {
                  return 0.5f; //pass as per your requirement
              }
          }
      }
      

      【讨论】:

      • overwrite calculateSpeedPerPixel 为我工作,调用smoothScrollToPosition(position) 时默认会使recycler view 像跳转一样,但是当覆盖此方法并返回0.5f 时效果很好
      【解决方案6】:
      android:animateLayoutChanges="false"
      

      【讨论】:

      • 那是什么?
      【解决方案7】:

      你需要使用“Picasso”库来异步加载图片,同时使用fit()函数确保你加载的图片大小与布局中image view的大小相近。此外,如果您在滚动视图中使用回收器视图,请确保将 nested scrolling 设置为 false。

      我使用以上三种方法解决了我的问题

      【讨论】:

        【解决方案8】:

        使用这里其他 cmets 所说的库。还要确保您没有嵌套在 Scrollview 中的 Recyclerviews。这也是我之前的不那么顺利的原因之一。

        【讨论】:

          【解决方案9】:

          用了 3 天,我解决了项目中的平滑滚动问题。

          问题是&lt;layer-list&gt; drawable 设置在item_user.xml 文件的背景中,因此需要 GPU 时间进行渲染,这就是滚动不流畅的原因。

          不要在适配器项中使用&lt;layer-list&gt; 或任何其他复杂的可绘制对象。

          【讨论】:

            【解决方案10】:

            添加这个

            animateLayoutChanges = true 
            

            在回收站视图 xml 中

            【讨论】:

            • 那是什么?
            猜你喜欢
            • 2017-01-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-03-09
            • 1970-01-01
            • 1970-01-01
            • 2016-03-19
            • 1970-01-01
            相关资源
            最近更新 更多