LazyColumnはJetpack Composeのcomposable関数で、要素の遅延読み込みを行う垂直リストを作成します。Columnとは異なり、LazyColumnは画面上に表示される要素のみを作成・構成し、スクロール時にそれらを再利用します。Google Android Documentation, 2025によると、LazyColumnは効率的なメモリ管理により、モバイルアプリケーションで大規模データセットを表示するための主要なツールです。
重要なポイント
LazyColumnは、遅延読み込みを備えた垂直スクロール可能なリストを実装するcomposable関数です。すべての子要素を一度にレンダリングするColumnとは異なり、LazyColumnはビューポート内にある要素のみを作成します。
LazyColumnの遅延読み込みメカニズムは要素の再利用に基づいています。スクロール中に要素が非表示になると、そのコンポジションとレイアウトを新しく表示される要素に再利用できます。これにより、特に長いリストでメモリとCPU時間を節約できます。
Android Developers Blog, 2024によると、LazyColumnはパフォーマンスを大幅に低下させることなく、数万の要素からなるリストを効率的に処理できます。LazyColumnの各要素にはキー(key)があり、リストが変更されたときにComposeが要素の状態を識別して保持するのに役立ちます。
LazyColumnはmodifier、state、contentPadding、reverseLayout、verticalArrangement、horizontalAlignmentのパラメータを受け入れます。コンテンツはDSL関数のitemsとitemを使用してラムダブロックで定義されます。
@Composable
fun SimpleLazyColumn() {
val itemsList = (1..100).toList()
LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(8.dp),
contentPadding = PaddingValues(16.dp)
) {
items(itemsList) { item ->
Text(text = "アイテム $item")
}
}
}
LazyColumnのDSLブロックは、コンテンツを追加するためのitems関数とitem関数を提供します。itemsはデータコレクション、キー、ファクトリ関数を受け取って要素を作成します。itemはリストに単一の静的要素を追加します。
itemsIndexedはitemsのバリアントで、データに加えて要素のインデックスも渡します。これは、別途計算せずに要素の位置を知る必要がある場合に便利です。items(size)はコレクションにバインドせずに要素数とファクトリのみを受け取ります。
itemsのkeyパラメータは各要素を一意に識別します。Material Design Guidelines, 2025によると、キーは要素の更新やアニメーション時のパフォーマンスを向上させます。Composeはキーによって特定の要素の移動や変更を追跡できるためです。
contentTypeを指定したitems関数により、LazyColumnは異なるタイプの要素の再利用を最適化できます。以下の例では、1つのリストにセクションヘッダーと通常の行を使用しています。
@Composable
fun MixedItemsList() {
LazyColumn {
item {
Text(
text = "ヘッダー",
style = MaterialTheme.typography.headlineMedium
)
}
items(
items = (1..20).toList(),
key = { it },
contentType = { "item" }
) { item ->
Text(text = "行 $item")
}
}
}
LazyListStateはLazyColumnの状態オブジェクトで、現在のスクロール位置、最初に表示される要素、オフセットを追跡します。rememberLazyListState()で作成し、LazyColumnのstateパラメータに渡すことができます。
LazyListStateはanimateScrollToItemとscrollToItemのメソッドを提供し、特定の要素へのプログラムによるスクロールを可能にします。animateScrollToItemはスムーズなスクロールアニメーションを作成し、scrollToItemは即座にスクロールします。どちらのメソッドもCompositionContext内のコルーチン内で呼び出す必要があります。
Android Developers, 2024によると、LazyListStateにはlayoutInfoも含まれており、表示要素のインデックス、オフセット、サイズに関する情報を提供します。これは分析、ビュートラッキング、無限スクロールの実装に役立ちます。
この例では、LazyColumnがLazyListStateを介して制御されています。ボタンをクリックすると、スムーズなアニメーションでリストがインデックス50の要素までスクロールします。
@Composable
fun ScrollableList() {
val listState = rememberLazyListState()
val scope = rememberCoroutineScope()
Column {
Button(
onClick = {
scope.launch {
listState.animateScrollToItem(50)
}
}
) {
Text("50までスクロール")
}
LazyColumn(state = listState) {
items((1..100).toList()) { item ->
Text(
text = "アイテム $item",
modifier = Modifier.padding(8.dp)
)
}
}
}
}
LazyColumnのパフォーマンスにおける重要な要素は、キーの適切な使用です。各要素はkeyパラメータを通じて一意で安定したキーを持つ必要があります。キーがないと、Composeはデータ変更時に要素を正しく再利用できず、再コンポジションが発生します。
contentTypeはLazyColumnにどの要素が同じレイアウトタイプかを伝えます。同じcontentTypeを持つ2つの要素がリサイクルプールに入ると、LazyColumnは再コンポジションなしでレイアウトを再利用できます。Android Developers Blog, 2024によると、contentTypeは異なる要素タイプのリストでパフォーマンスを30~50%向上させます。
LazyColumnでは、ファクトリ関数内で不安定なパラメータを避けることも重要です。要素のパラメータが変更されるたびに、Composeはその要素を再コンポーズします。安定した値にはrememberとderivedStateOfを使用することで、再コンポジションの回数を減らせます。
| 要因 | 影響 | 推奨事項 |
|---|---|---|
| キー(key) | 重大 | itemsには常に一意で安定したkeyを設定してください |
| contentType | 顕著 | 再利用を最適化するために要素タイプを指定してください |
| 要素のサイズ | 中程度 | 可能な場合は固定サイズを使用してください |
| ネストされたリスト | 重大 | LazyColumn内のLazyColumnは避けてください — LazyVerticalGridを使用してください |
stickyHeaderはLazyColumnのDSL関数で、スクロール中にセクションヘッダーをリスト上部に固定します。次のセクションが上部に到達すると、そのヘッダーが現在のヘッダーを置き換えます。この動作は連絡先リストやカレンダーでおなじみです。
stickyHeaderはitemと同様にキーとファクトリ関数を受け取ります。通常のitemとは異なり、stickyHeaderはセクションのコンテンツをスクロールしている間も表示されたままになります。セクションが完全にスクロールされると、次のセクションのヘッダーが前のヘッダーを押し出します。
Material Design Guidelines, 2025によると、sticky headerは長いリストのナビゲーションを改善し、ユーザーの認知負荷を軽減します。sticky headerを実装するには、items要素に対して正しい位置でセクションヘッダーをstickyHeaderでラップするだけです。
@Composable
fun SectionedList(sections: Map<String, List<String>>) {
LazyColumn {
sections.forEach { (header, items) ->
stickyHeader {
Text(
text = header,
modifier = Modifier.background(Color.White)
.padding(16.dp)
)
}
items(items) { item ->
Text(text = item, modifier = Modifier.padding(8.dp))
}
}
}
}
よくある質問
Columnはすべての要素を一度にレンダリングし、20~30要素までのリストに適しています。LazyColumnは表示要素のみを作成しスクロール時に再利用するため、パフォーマンスを低下させることなく数千の要素を扱えます。
verticalArrangementパラメータでArrangement.spacedByを使用するか、インデックスによる区切りを持つitems関数を使用します。複雑な区切りの場合は、リスト要素の間にDivider()を持つ別のitemを追加してください。
LazyColumnは、安定したキーが使用されている場合、データコレクションが変更されると自動的に再コンポーズされます。mutableStateListOfやStateFlowを介して検出されたデータ変更により、変更された要素のみが再描画されます。
LazyColumnの中にLazyColumnを直接ネストすることは推奨されません — 両方に独立したスクロールがあり、ジェスチャーの競合が発生します。代わりに、スクロール可能なSection内でLazyColumnを持つ通常のColumn、またはグリッドにはLazyVerticalGridを使用してください。
LazyListState.layoutInfo.visibleItemsInfoを使用し、最後に表示されている要素のインデックスを要素の総数と比較します。無限スクロールの場合は、最後に表示される要素がリストの終わりに近づいたときを追跡します。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。