使用两个 RecyclerView 滚动页面(片段):最先进的技术以及回收情况如何?

Scrolling a page (fragment) with two RecyclerViews: State of the art & how about recycling?

我在一个布局中有两个 RecyclerView。直到现在我都无法滚动页面本身,只能滚动每个RecyclerView,感觉很奇怪。现在我想找出滚动带有两个 RecyclerView 的页面的最佳实践。我听说当我把它们放在 NestedScrollView 中时,它们就停止回收它们的视图了。

  1. RecyclerView 放入 NestedScrollView 会禁用 RecyclerView 中的项目回收是真的吗?
  2. 特别是如果数字 1 为真,当前推荐的启用具有两个 Recyclerview 的页面滚动的方法是什么?

更新 这是我的布局。假设 recycler1recycler2 不携带相关的项目,所以将它们放在一个 RecyclerView 中(使用不同的视图类型)对我来说在语义上是错误的。

<androidx.constraintlayout.widget.ConstraintLayout
    android:id="@+id/layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/text1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:text="first title"
        app:layout_constraintBottom_toTopOf="@+id/recycler1"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text1"
        tools:itemCount="3"
        tools:listitem="@layout/item_category" />

    <TextView
        android:id="@+id/text2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginTop="24dp"
        android:text="second title"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/recycler1" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginLeft="16dp"
        android:layout_marginEnd="16dp"
        android:layout_marginRight="16dp"
        android:orientation="vertical"
        app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/text2"
        tools:itemCount="3"
        tools:listitem="@layout/item_category" />

</androidx.constraintlayout.widget.ConstraintLayout>

NestedScrollView - 的确如此。 NestedScrollView 的重点是它计算整个回收器视图大小及其所有子项要做到这一点,它需要渲染列表的所有子项 - 因此实际上 Android 矛盾地无法 RecycleViews 在 RecyclerView 中。对于没有分页的小列表还可以,但是对于大列表来说这是一个主要的性能问题。

该问题的解决方案在于设计(或程序设计)领域。不要使用两个 RecyclerView,而是使用一个 two view types。第二种方法 - 将包含两个列表的屏幕分成两个屏幕,每个屏幕包含一个列表。

通常有两个需要相互滚动的列表是糟糕的设计 - 所以尽量避免这样的解决方案。

希望对您有所帮助。

这正是 ConcatAdapter as per the Concatenate adapters sequentially with ConcatAdapter blog post 的用例:

ConcatAdapter is a new class available in recyclerview:1.2.0-alpha02 which enables you to sequentially combine multiple adapters to be displayed in a single RecyclerView. This enables you to better encapsulate your adapters rather than having to combine many data sources into a single adapter, keeping them focused and re-usable.

这允许您将布局编写为单个 RecyclerView,它可以正确回收视图,同时保持每个单独的适配器(及其数据加载)独立。

在你的情况下,你应该考虑实际上有 4 个适配器 - 两个简单的标题(或你可以编写的相同 TitleAdapter 的两个实例),再加上每个以前的适配器。

然后你将通过传递所有 4 个适配器来构造你的 ConcatAdapter 以使一个可滚动 RecyclerView:

val firstTitleAdapter = TitleAdapter("first title")
val firstListAdapter: FirstListAdapter = …

val secondTitleAdapter = TitleAdapter("second title")
val secondListAdapter: SecondListAdapter = …

val concatAdapter = ConcatAdapter(firstTitleAdapter, firstListAdapter, 
   secondTitleAdapter, secondListAdapter)
recyclerView.adapter = concatAdapter