Membuat tata letak daftar-detail

Daftar-detail adalah pola UI yang terdiri dari tata letak panel ganda dengan satu panel menampilkan daftar item dan panel lain menampilkan detail item yang dipilih dari daftar.

Pola ini sangat berguna untuk aplikasi yang memberikan informasi mendalam tentang elemen koleksi besar, misalnya, program email yang memiliki daftar email dan konten mendetail dari setiap pesan email. Detail daftar juga dapat digunakan untuk jalur yang kurang penting seperti membagi preferensi aplikasi ke dalam daftar kategori dengan preferensi untuk setiap kategori di panel detail.

Mengimplementasikan pola UI dengan ListDetailPaneScaffold

ListDetailPaneScaffold adalah composable yang menyederhanakan implementasi pola daftar-detail di aplikasi Anda. Scaffold daftar-detail dapat terdiri dari maksimal tiga panel: panel daftar, panel detail, dan panel tambahan opsional. Scaffold menangani penghitungan ruang layar. Jika ukuran layar yang memadai tersedia, panel detail akan ditampilkan bersama panel daftar. Pada ukuran layar kecil, scaffold akan otomatis beralih untuk menampilkan daftar atau panel detail layar penuh.

Panel detail yang ditampilkan di samping halaman daftar.
Gambar 1. Jika ukuran layar yang cukup tersedia, panel detail akan ditampilkan bersama panel daftar.
Setelah item dipilih, panel detail akan mengisi seluruh layar.
Gambar 2. Jika ukuran layar terbatas, panel detail (karena item telah dipilih) akan mengambil alih seluruh ruang.

Mendeklarasikan dependensi

ListDetailPaneScaffold adalah bagian dari library tata letak adaptif Material 3.

Tambahkan tiga dependensi terkait berikut ke file build.gradle aplikasi atau modul Anda:

Kotlin

implementation("androidx.compose.material3.adaptive:adaptive")
implementation("androidx.compose.material3.adaptive:adaptive-layout")
implementation("androidx.compose.material3.adaptive:adaptive-navigation")

Groovy

implementation 'androidx.compose.material3.adaptive:adaptive'
implementation 'androidx.compose.material3.adaptive:adaptive-layout'
implementation 'androidx.compose.material3.adaptive:adaptive-navigation'
  • adaptif — Elemen penyusun tingkat rendah seperti HingeInfo dan Posture
  • adaptive-layout — Tata letak adaptif seperti ListDetailPaneScaffold dan SupportingPaneScaffold
  • adaptive-navigation — Composable untuk menavigasi dalam dan antar-panel

Penggunaan dasar

Terapkan ListDetailPaneScaffold sebagai berikut:

  1. Gunakan class yang mewakili konten yang akan dipilih. Class ini harus berupa Parcelable untuk mendukung penyimpanan dan pemulihan item daftar yang dipilih. Gunakan plugin kotlin-parcelize untuk membuat kode bagi Anda.

    @Parcelize
    class MyItem(val id: Int) : Parcelable

  2. Buat ThreePaneScaffoldNavigator dengan rememberListDetailPaneScaffoldNavigator dan tambahkan BackHandler. Navigator ini digunakan untuk berpindah antarpanel daftar, detail, dan tambahan. Dengan mendeklarasikan jenis generik, navigator juga melacak status scaffold (yaitu, MyItem yang ditampilkan). Karena jenis ini dapat dipartisi, status dapat disimpan dan dipulihkan oleh navigator untuk menangani perubahan konfigurasi secara otomatis. BackHandler memberikan dukungan untuk kembali menggunakan gestur atau tombol kembali sistem. Perilaku tombol kembali yang diharapkan untuk ListDetailPaneScaffold bergantung pada ukuran jendela dan nilai scaffold saat ini. Jika ListDetailPaneScaffold dapat mendukung kembali dengan status saat ini, canNavigateBack() adalah true, yang mengaktifkan BackHandler.

    val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
    
    BackHandler(navigator.canNavigateBack()) {
        navigator.navigateBack()
    }

  3. Teruskan scaffoldState dari navigator ke composable ListDetailPaneScaffold.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        // ...
    )

  4. Berikan implementasi panel daftar Anda ke ListDetailPaneScaffold. Gunakan AnimatedPane untuk menerapkan animasi panel default selama navigasi. Kemudian, gunakan ThreePaneScaffoldNavigator untuk membuka panel detail, ListDetailPaneScaffoldRole.Detail, dan menampilkan item yang diteruskan.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane = {
            AnimatedPane {
                MyList(
                    onItemClick = { item ->
                        // Navigate to the detail pane with the passed item
                        navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                    }
                )
            }
        },
        // ...
    )

  5. Sertakan implementasi panel detail Anda di ListDetailPaneScaffold. Setelah navigasi selesai, currentDestination akan berisi panel yang dituju aplikasi Anda, termasuk konten yang ditampilkan di panel. Properti content adalah jenis yang sama dengan yang ditentukan dalam panggilan remember asli (MyItem dalam contoh ini), sehingga Anda juga dapat mengakses properti untuk data apa pun yang perlu ditampilkan.

    ListDetailPaneScaffold(
        directive = navigator.scaffoldDirective,
        value = navigator.scaffoldValue,
        listPane =
        // ...
        detailPane = {
            AnimatedPane {
                navigator.currentDestination?.content?.let {
                    MyDetails(it)
                }
            }
        },
    )

Setelah menerapkan langkah-langkah di atas, kode Anda akan terlihat seperti ini:

val navigator = rememberListDetailPaneScaffoldNavigator<MyItem>()

BackHandler(navigator.canNavigateBack()) {
    navigator.navigateBack()
}

ListDetailPaneScaffold(
    directive = navigator.scaffoldDirective,
    value = navigator.scaffoldValue,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    navigator.navigateTo(ListDetailPaneScaffoldRole.Detail, item)
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            navigator.currentDestination?.content?.let {
                MyDetails(it)
            }
        }
    },
)