【问题标题】:Having RecyclerView inside a NestedScrollView calls onBindView for all the items在 NestedScrollView 中使用 RecyclerView 为所有项目调用 onBindView
【发布时间】:2018-06-02 09:55:52
【问题描述】:

我有两个RecyclerViews 垂直放置在LinearLayout 中。我需要使它们都可以滚动,这就是为什么我将LinearLayout 放入NestedScrollView

这是我的布局文件。

<android.support.v4.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true"
android:scrollbars="none">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/featured_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/all_topic_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
</LinearLayout>

另外,我正在禁用 Java 代码中的嵌套滚动。

disableNestedScrolling(findViewById(R.id.all_topic_list));
disableNestedScrolling(findViewById(R.id.featured_list));

我的RecylerView库版本是26.1.0

这工作得很好,但随后onBindViewHolder 方法被调用用于列表中的所有项目。理想情况下,应该只为列表中的可见项目调用它。

我认为问题正在发生,因为我将wrap_content 提供给RecyclerViewthis 问题的很多答案表明该问题已在 v23.2.1 中解决,但我已经在使用 v26.1.0。如何解决这个问题?

【问题讨论】:

  • 我想你可以查看answer here。您可以考虑在一个 RecyclerView 中包含两组数据,而不是使用两个单独的 RecyclerView,以便更好地优化您的视图。
  • 数据来自两个不同的api,因此我们需要维护两个不同的recyclerview。另外,第一个是水平的recyclerview,第二个是垂直的,所以我的情况是不可能的。
  • 我支持使用单个 RecyclerView 的建议。您可以让第一个元素成为另一个水平的 RecyclerView 。我不确定为什么来自两个 api 的数据是一个问题,只是创建适配器以正确处理不同的视图类型。

标签: android android-recyclerview


【解决方案1】:

我遇到了完全相同的问题。 RecyclerViews 并不意味着放置在具有相同滚动方向的滚动容器内。视图回收仅在高度设置为MATCH_PARENT时有效。

取决于NestedScrollView 内内容的复杂性和RecyclerView 项目的预期数量:

  1. 忽略问题。如果只有几个简单的项目,你可以 根本不需要视图回收。

    当我遇到问题时,我分析了其他流行应用程序的布局:例如,WhatsApp 在其应用程序的某些部分仅使用RecyclerViews(或ListViews 与视图回收)。

    特别是,this group settings screen 与数百个可能的项目是由多个 ListViews 包裹的 ScrollView 组成,没有任何视图回收。

  2. NestedScrollView 替换为单个 ReyclerView with multiple item types 并将所有可滚动内容放入其中。如果您需要视图回收,这是要走的路。

    请注意,您还必须将 NestedScrollView 中的所有其他内容(页眉和页脚、间距)转换为 RecyclerView 项目,并使用它们自己的 ViewHolders

    如果设置相当简单,我建议您按照上面的链接在不使用其他库的情况下实现它。


有几个不同的库可用于解决您的问题(它们都遵循第二种方法,使用单个 RecyclerView),但大多数都带有许多您可能不需要的额外功能:

RendererRecyclerViewAdapter

它带有一个ViewRenderer/ViewModel interface,它的作用类似于 单个项目类型的“部分” RecyclerView。你会创建一个 为每个项目类型,然后将它们注册到一个适配器中。

Epoxy

由 airbnb 创建并在其应用中大量使用的库/框架。 他们有很多可滚动的内容(类似于网页) 很多不同的项目类型。环氧树脂还有助于组成 页面上的不同项目,它处理动画时 内容或其顺序发生变化。如果您只需要一个屏幕,那就太多了。

Litho

由 Facebook 创建的完整 UI 框架,带有自己的渲染引擎,可替代 xml 布局等等。据我了解,它允许您处理大量项目(如 Facebook 时间线),并且视图回收是自动处理的。与 Epoxy 一样,只有当您的应用包含诸如具有许多不同项目类型的无休止滚动之类的内容并且您确实需要性能时,您才会使用它。


我尝试了 Epoxy 和 RendererRecyclerViewAdapter,但毕竟我创建了自己的多项目类型适配器。不到 100 行代码就可以创建它。

【讨论】:

  • RendererRecyclerViewAdapter 还支持嵌套 RecyclerViews 和其他功能。 =)
【解决方案2】:

RecyclerView:1.2.0-alpha04开始我们可以使用ConcatAdapter来解决这个问题 https://developer.android.com/reference/androidx/recyclerview/widget/ConcatAdapter

【讨论】:

  • 请说明如何使用ConcatAdapter 解决问题
【解决方案3】:

我通过在每个 recyclerview 中添加 20 个项目来尝试您的问题,其中 NestedScrollView 应用程序调用了 onBindViewHolder 方法 40 次。当您在 Java 代码中禁用嵌套滚动时,我建议使用 Scrollview。通过使用 ScrollView 应用程序调用 onBindViewHolder 33 次。


如果您将 recyclerView 的高度固定为特定大小而不是“匹配父级”,它将大大减少对 onBindViewHolder 的调用。

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">

<android.support.v7.widget.LinearLayoutCompat
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.vishal.my2.MainActivity">
<android.support.v7.widget.RecyclerView
    android:id="@+id/featured_list"
    android:layout_width="match_parent"
    android:layout_height="300dp" />

<android.support.v7.widget.RecyclerView
    android:id="@+id/all_topic_list"
    android:layout_width="match_parent"
    android:layout_height="300dp" />
</android.support.v7.widget.LinearLayoutCompat>
</ScrollView>

如果为recyclerView 的高度指定硬编码值不符合您的应用程序要求,那么您可以尝试使用ListView 代替recyclerView。如果我错了,请原谅我,这是我第一次回答任何问题。

【讨论】:

    【解决方案4】:

    将此添加到嵌套滚动视图android:fillViewport="false"

    【讨论】:

    • 这不起作用。你也愿意解释一下为什么这对你有用吗?
    • android:fillViewport="true" 将使 recyclerview 一次加载所有项目,但将其设置为 false 将使 recyclerview 包装其内容。我还可以在您的代码中看到您已禁用嵌套滚动,在这种情况下您将无法单独滚动回收站视图。
    猜你喜欢
    • 1970-01-01
    • 2018-08-02
    • 2017-03-05
    • 1970-01-01
    • 2021-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多