RecyclerView を Lazy リストに移行する

RecyclerView は、大規模なデータセットを効率的に表示するための View コンポーネントです。RecyclerView を使用すると、データセット内のアイテムごとにビューを作成する代わりに、小さなビュープールを保持し、アイテムをスクロールする際にそれらのビューをリサイクルすることで、アプリのパフォーマンスを向上させます。

Compose では、Lazy リストを使用して同じことを実現できます。このページでは、Compose で Lazy リストを使用するように RecyclerView の実装を移行する方法について説明します。

移行手順

RecyclerView の実装を Compose に移行するには、次の手順を行います。

  1. UI 階層から RecyclerView をコメントアウトまたは削除し、階層にまだ存在しない場合は ComposeView を追加して置き換えます。これは、追加する Lazy リストのコンテナです。

          <FrameLayout
              android:layout_width="match_parent"
              android:layout_height="match_parent">
    
      <!--    <androidx.recyclerview.widget.RecyclerView-->
      <!--            android:id="@+id/recycler_view"-->
      <!--            android:layout_width="match_parent"-->
      <!--            android:layout_height="match_parent />"-->
    
              <androidx.compose.ui.platform.ComposeView
                  android:id="@+id/compose_view"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent" />
    
          </FrameLayout>
    
  2. RecyclerView のレイアウト マネージャーに基づいて、必要な Lazy リスト コンポーザブルのタイプを決定します(以下の表を参照)。選択したコンポーザブルは、前の手順で追加した ComposeView のトップレベル コンポーザブルになります。

    LayoutManager

    コンポーザブル

    LinearLayoutManager

    LazyColumnまたはLazyRow

    GridLayoutManager

    LazyVerticalGrid または LazyHorizontalGrid

    StaggeredGridLayoutManager

    LazyVerticalStaggeredGridまたはLazyHorizontalStaggeredGrid

    // recyclerView.layoutManager = LinearLayoutManager(context)
    composeView.setContent {
        LazyColumn(Modifier.fillMaxSize()) {
            // We use a LazyColumn since the layout manager of the RecyclerView is a vertical LinearLayoutManager
        }
    }

  3. RecyclerView.Adapter 実装で、ビュータイプごとに対応するコンポーザブルを作成します。通常、各ビュータイプは ViewHolder サブクラスにマッピングされますが、常にそうなるとは限りません。これらのコンポーザブルは、リスト内のさまざまなタイプの要素の UI 表現として使用されます。

    @Composable
    fun ListItem(data: MyData, modifier: Modifier = Modifier) {
        Row(modifier.fillMaxWidth()) {
            Text(text = data.name)
            // … other composables required for displaying `data`
        }
    }

    RecyclerView.AdapteronCreateViewHolder() メソッドと onBindViewHolder() メソッドのロジックは、これらのコンポーザブルと、コンポーザブルに指定した状態に置き換えられます。Compose では、アイテムのコンポーザブルの作成とそれへのデータのバインドは分離されません。これらのコンセプトは統合されています。

  4. Lazy リストの content スロット(後置ラムダ パラメータ)内で、items() 関数(または同等のオーバーロード)を使用してリストのデータを反復処理します。itemContent ラムダで、データに適したコンポーザブル アイテムを呼び出します。

    val data = listOf<MyData>(/* ... */)
    composeView.setContent {
        LazyColumn(Modifier.fillMaxSize()) {
            items(data) {
                ListItem(it)
            }
        }
    }

一般的なユースケース

アイテムの装飾

RecyclerView には ItemDecoration という概念があり、これを使用するとリスト内のアイテムに特別な描画を追加できます。たとえば、ItemDecoration を追加してアイテム間に分割線を追加できます。

val itemDecoration = DividerItemDecoration(recyclerView.context, LinearLayoutManager.VERTICAL)
recyclerView.addItemDecoration(itemDecoration)

Compose には、アイテム デコレーションに相当するコンセプトはありません。代わりに、リスト内の UI 装飾をコンポジションに直接追加できます。たとえば、リストに分割線を追加するには、各アイテムの後に Divider コンポーザブルを使用します。

LazyColumn(Modifier.fillMaxSize()) {
    itemsIndexed(data) { index, d ->
        ListItem(d)
        if (index != data.size - 1) {
            Divider()
        }
    }
}

アイテム アニメーション

ItemAnimatorRecyclerView に設定すると、アダプターに変更が加えられたときにアイテムの外観をアニメーション化できます。デフォルトでは、RecyclerViewDefaultItemAnimator を使用します。これは、削除、追加、移動のイベントに関する基本的なアニメーションを提供します。

Lazy リストには、animateItemPlacement 修飾子を使った同様の概念があります。詳しくは、アイテム アニメーションをご覧ください。

参考情報

RecyclerView を Compose に移行する方法について詳しくは、次のリソースをご覧ください。