Episode ini mengoptimalkan daftar: LazyColumn, LazyRow, dan LazyVerticalGrid, rendering item yang efisien dengan key, integrasi Paging 3 untuk data tak berujung, serta animasi dalam lazy list.

Di episode 4 kalian berkenalan dengan LazyColumn. Sekarang saatnya memanfaatkannya secara penuh. List adalah tulang punggung aplikasi sosial, e-commerce, dan dashboard — dan cara kalian merender list menentukan kelancaran aplikasi.
Lazy list di Compose hanya membuat item yang terlihat, memakai ulang layout yang sudah ada, dan membuang yang jauh dari layar. Kuncinya adalah memberi tahu Compose item mana yang sama lewat key.
Episode 9 ini meliputi lazy list dasar, item reuse dan key, grid layout, integrasi Paging 3, serta animasi.
LazyColumn merender daftar vertikal, LazyRow horizontal. Keduanya memakai blok DSL dengan fungsi item dan items:
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
item { HeaderList() }
items(produk) { produk ->
KartuProduk(produk)
}
}contentPadding memberi jarak dari tepi layar, spacedBy(12.dp) memberi jarak antar item, dan campuran item dengan items memungkinkan header di atas daftar data. Satu LazyColumn dapat menampung banyak tipe konten.
Untuk katalog dan galeri, LazyVerticalGrid menyusun item dalam kolom:
LazyVerticalGrid(
columns = GridCells.Fixed(2),
modifier = Modifier.fillMaxSize(),
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalArrangement = Arrangement.spacedBy(12.dp)
) {
items(foto) { foto ->
KartuFoto(foto)
}
}GridCells.Fixed(2) menetapkan dua kolom tetap, dan GridCells.Adaptive(160.dp) menyesuaikan jumlah kolom dengan lebar layar. Untuk grid adaptif, pilih Adaptive; untuk tata letak pasti, pilih Fixed.
Setiap item lazy list harus diberi key yang stabil. Key memberi tahu Compose bahwa item tersebut sama meski posisinya bergeser — penting untuk mempertahankan state item dan animasi:
items(items = produk, key = { it.id }) { produk ->
KartuProduk(produk)
}key = { it.id } menggunakan ID produk sebagai identitas. Tanpa key, Compose menggunakan posisi sebagai identitas, sehingga state item bisa salah menempel ketika daftar berubah — detail yang juga penting untuk performa di episode 15.
Saat list menampung tipe item berbeda, gunakan contentType agar Compose memakai ulang layout dengan benar:
items(
items = feed,
key = { it.id },
contentType = { it.jenis }
) { item ->
when (item.jenis) {
"teks" -> KartuTeks(item)
"gambar" -> KartuGambar(item)
}
}contentType = { it.jenis } mengelompokkan item berdasarkan tipe sehingga Compose tidak mengganti layout secara sia-sia.
Paging 3 mengalirkan halaman data ke UI. collectAsLazyPagingItems mengubah Flow<PagingData<T>> menjadi objek yang bisa dikonsumsi LazyColumn:
val pagingItems = viewModel.pagingFlow.collectAsLazyPagingItems()
LazyColumn {
items(pagingItems.itemCount) { index ->
pagingItems[index]?.let { artikel ->
KartuArtikel(artikel)
}
}
}pagingItems.itemCount berubah seiring halaman dimuat, dan pagingItems[index] mengembalikan null saat item masih dimuat — di sinilah loading placeholder dipasang. Paging 3 menangani loading berikutnya secara otomatis saat pengguna mendekati akhir list.
Pantau loadState untuk menampilkan loading dan retry:
when (pagingItems.loadState.refresh) {
is LoadState.Loading -> LoadingIndikator()
is LoadState.Error -> {
Text("Gagal memuat", Modifier.padding(16.dp))
}
else -> {}
}loadState.refresh menunjukkan status muatan pertama, dan loadState.append status pemuatan halaman berikutnya. Kedua status ini dipakai untuk menampilkan indikator di bawah list saat scroll. Untuk mensimulasikan scroll selama pengujian manual, adb shell input swipe 540 1600 540 400 menggeser layar ke bawah di emulator.
Lazy list mendukung animasi penambahan dan penghapusan item:
LazyColumn {
items(items = tugas, key = { it.id }) { tugas ->
Row(
modifier = Modifier
.fillMaxWidth()
.animateItem()
) {
Text(tugas.judul)
}
}
}Modifier.animateItem() menganimasikan perpindahan, penambahan, dan penghapusan item. Detail animasi lebih dalam akan dibahas di episode 12; di sini yang penting adalah key stabil menjadi prasyarat animasi list bekerja benar.
Episode 9 mengoptimalkan daftar: LazyColumn, LazyRow, dan LazyVerticalGrid untuk tata letak beragam, key dan contentType untuk rendering yang efisien, integrasi Paging 3 dengan collectAsLazyPagingItems dan loadState, serta animasi item dengan animateItem.
Inti yang harus dibawa pulang:
key yang stabil mempertahankan identitas dan state item.contentType memungkinkan reuse layout untuk item sejenis.animateItem butuh key stabil untuk bekerja dengan benar.Di episode 10 selanjutnya kita akan membahas side effects dan coroutines — LaunchedEffect, SideEffect, dan DisposableEffect, integrasi coroutine dengan Compose, loading states dan panggilan jaringan, serta efek yang sadar lifecycle.