LazyColumnとColumnはどちらも一覧(リスト)表示するUIです。
記述方法は違いますが、スクロールしたり、アイテムを制御したり、ほぼ同じことが出来ます。
ただし、両者の特徴により、向き不向きがあります。よく違いを理解して、適材適所で使い分けが必要です。
ここでは、両者の違いをまとめました。
※環境:Android Studio Koala | 2024.1.1
Kotlin 1.9.0
Compose Compiler 1.5.1
androidx.compose.foundation:foundation 1.6.8
Columnとの違い
LazyColumnは、「複数のデータやオブジェクト」または「コレクション」を、一覧表示するUIです。
同様なことがColumnでも出来ます。しかし、表に示すような特徴があります。
評価項目 | Column | LazyColumn | ||
---|---|---|---|---|
(1) | 記述の容易さ | |||
(2) | パフォーマンス | 小規模リスト(表示範囲+α程度) | ||
大規模リスト | ||||
(3) | アイテムの制御 ※制御:変更、追加、削除、移動 | |||
※◎:とても適する、○:適する、△:あまり適しない、×:適しない |
適材適所で使い分けが必要です。
記述の容易さ
LazyColumnはDSLを用いてアイテムの並びを記述します。ですので、DSLの理解が必要です。
※各DSLの詳細は「Compose LazyColumn:LazyListScope DSL」を参照
Column( modifier = Modifier .fillMaxSize() .verticalScroll(rememberScrollState()), verticalArrangement = Arrangement.spacedBy(2.dp), ) { headerItem() playerList.forEach { playerItem(it.name, it.level, it.score) } }
LazyColumn( modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(2.dp) ) { @OptIn(ExperimentalFoundationApi::class) stickyHeader { // DSLコマンド headerItem() } items(playerList) { item -> // DSLコマンド playerItem(item.name, item.level, item.score) } }
両者は同じ表示になります。スクロールも可能です。
パフォーマンス
小規模リストはColumn、大規模リストはLazyColumnが適しています。
ColumnColumnは初回のコンポーズで、すべてのアイテムをComposition内に展開します。これは、1000個のアイテムがあれば1000個のUIが展開される事を意味します。
ですので、アイテムが多くなればなるほど、端末のリソース(メモリーやCPU処理能力)をより多く消費し、その影響でパフォーマンスは低下します。
スクロールは、Composition内のアイテム上をウィンドウが移動するイメージです。
LazyColumnLazyColumnは初回のコンポーズで、表示分のアイテムをComposition内に展開します。サンプルは、6個のアイテムが表示可能なので、6個のUIが展開されています。
ですので、アイテムが多くなったとしても、端末のリソースの消費量は一定で、パフォーマンスの低下は起こりません。
スクロールは、スクロール先のUIを事前準備する関係で、Composition内のアイテム数が多少増加しますが、表示可能なアイテム数のx1.8~2.0程度です。その後は、既存のアイテムを使い回し、数は変化しません。
アイテムの制御
ColumnもLazyColumnもアイテムの制御(変更/追加/移動/削除)は可能です。また、不要な再Composeを排除するために、アイテムをキーで認識することも可能です。
ただし、LazyColumnのキーはLazyListScope DSL内に組み込まれているので、個別にkey関数を使う必要がありません。
@Stable data class NumData(val id: Int, var num: Int) private var ID: Int = 100 private fun newData() = try { NumData(ID, ID) } finally { ID++ } @Composable private fun SampleList_a(datas: List<NumData>) { val _datas = remember { mutableStateListOf<NumData>().apply { addAll(datas) } } Column { _datas.forEach { key(it.id) { ItemBox { Text(text = "Item %02d (Column)".format(it.num)) } } } } Button( onClick = { _datas.add(4, newData()) } ) { Text(text = "ins")} }
@Stable data class NumData(val id: Int, var num: Int) private var ID: Int = 100 private fun newData() = try { NumData(ID, ID) } finally { ID++ } @Composable private fun SampleList_1(datas: List<NumData>) { val _datas = remember { mutableStateListOf<NumData>().apply { addAll(datas) } } LazyColumn { items(items = _datas, key = { it.id }) { ItemBox { Text(text = "Item %02d".format(it.num)) } } } Button( onClick = { _datas.add(4, newData()) }, ) { Text(text = "ins")} }
※DSLの詳細は「Compose LazyColumn:LazyListScope DSL」を参照
※「アイテムの制御」の詳細は「… LazyColumn:アイテムの制御(Ch…)」を参照
関連記事: