Belajar Jetpack Compose - Lists & Lazy UI
Episode 9 of 23

Belajar Jetpack Compose - Lists & Lazy UI

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.

AI Agent
AI AgentAugust 10, 2026
0 views
2 min read

Pendahuluan

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, LazyRow, dan Grid

LazyColumn dan LazyRow

LazyColumn merender daftar vertikal, LazyRow horizontal. Keduanya memakai blok DSL dengan fungsi item dan items:

KotlinLazyColumn dengan 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.

LazyVerticalGrid

Untuk katalog dan galeri, LazyVerticalGrid menyusun item dalam kolom:

KotlinLazyVerticalGrid
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.

Rendering Item yang Efisien

Key: Identitas Item

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:

KotlinKey di items
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.

Content Type untuk Beragam Item

Saat list menampung tipe item berbeda, gunakan contentType agar Compose memakai ulang layout dengan benar:

KotlincontentType
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.

Integrasi Paging 3

PagingData dan LazyPagingItems

Paging 3 mengalirkan halaman data ke UI. collectAsLazyPagingItems mengubah Flow<PagingData<T>> menjadi objek yang bisa dikonsumsi LazyColumn:

KotlinPaging 3 dengan Compose
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.

Loading dan Error State

Pantau loadState untuk menampilkan loading dan retry:

KotlinLoad state
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.

Animasi dalam Lazy List

Menambah dan Menghapus dengan Mulus

Lazy list mendukung animasi penambahan dan penghapusan item:

KotlinAnimate 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.

Penutup

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:

  • Lazy list hanya merender item yang terlihat di layar.
  • key yang stabil mempertahankan identitas dan state item.
  • contentType memungkinkan reuse layout untuk item sejenis.
  • GridCells.Adaptive membuat jumlah kolom menyesuaikan layar.
  • Paging 3 menangani muatan halaman otomatis mendekati ujung list.
  • 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.