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.

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.

Mengimplementasikan Pola Daftar-Detail dengan NavigableListDetailPaneScaffold

NavigableListDetailPaneScaffold adalah composable yang menyederhanakan penerapan tata letak detail daftar di Jetpack Compose. Class ini menggabungkan ListDetailPaneScaffold dan menambahkan navigasi bawaan dan animasi kembali prediktif.

Scaffold detail daftar mendukung hingga tiga panel:

  1. Panel daftar: Menampilkan kumpulan item.
  2. Panel detail: Menampilkan detail item yang dipilih.
  3. Panel tambahan (opsional): Memberikan konteks tambahan jika diperlukan.

Scaffold beradaptasi berdasarkan ukuran jendela:

  • Di jendela besar, panel daftar dan detail akan muncul berdampingan.
  • Di jendela kecil, hanya satu panel yang terlihat dalam satu waktu, yang beralih saat pengguna menavigasi.

Mendeklarasikan dependensi

NavigableListDetailPaneScaffold adalah bagian dari library navigasi 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
  • tata letak adaptif: Tata letak adaptif seperti ListDetailPaneScaffold dan SupportingPaneScaffold
  • adaptive-navigation: Composable untuk menavigasi dalam dan di antara panel, serta tata letak adaptif yang mendukung navigasi secara default seperti NavigableListDetailPaneScaffold dan NavigableSupportingPaneScaffold

Pastikan project Anda menyertakan compose-material3-adaptive versi 1.1.0-beta1 atau yang lebih tinggi.

Memilih untuk menggunakan gestur kembali prediktif

Untuk mengaktifkan animasi kembali prediktif di Android 15 atau yang lebih rendah, Anda harus memilih untuk mendukung gestur kembali prediktif. Untuk menerapkan, tambahkan android:enableOnBackInvokedCallback="true" ke tag <application> atau setiap tag <activity> dalam file AndroidManifest.xml Anda. Untuk informasi selengkapnya, lihat Memilih untuk menggunakan gestur kembali prediktif.

Setelah aplikasi Anda menargetkan Android 16 (API level 36) atau yang lebih tinggi, kembali prediktif diaktifkan secara default.

Penggunaan dasar

Terapkan NavigableListDetailPaneScaffold sebagai berikut:

  1. Gunakan class yang mewakili konten yang dipilih. Gunakan class Parcelable untuk mendukung penyimpanan dan pemulihan item daftar yang dipilih. Gunakan plugin kotlin-parcelize untuk membuat kode bagi Anda.
  2. Buat ThreePaneScaffoldNavigator dengan rememberListDetailPaneScaffoldNavigator.

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 dipaketkan, status dapat disimpan dan dipulihkan oleh navigator untuk menangani perubahan konfigurasi secara otomatis.

  1. Teruskan navigator ke composable NavigableListDetailPaneScaffold.

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

  3. Sertakan implementasi panel detail Anda di NavigableListDetailPaneScaffold.

Setelah navigasi selesai, currentDestination akan berisi panel yang dituju aplikasi Anda, termasuk konten yang ditampilkan di panel. Properti contentKey adalah jenis yang sama dengan yang ditentukan dalam panggilan asli sehingga Anda dapat mengakses data apa pun yang perlu ditampilkan.

  1. Secara opsional, ubah defaultBackBehavior di NavigableListDetailPaneScaffold. Secara default, NavigableListDetailPaneScaffold menggunakan PopUntilScaffoldValueChange untuk defaultBackBehavior.

Jika aplikasi Anda memerlukan pola navigasi kembali yang berbeda, Anda dapat mengganti perilaku ini dengan menentukan opsi BackNavigationBehavior lain.

BackNavigationBehavior opsi

Bagian berikut menggunakan contoh aplikasi email dengan daftar email di satu panel dan tampilan mendetail di panel lainnya.

Perilaku ini berfokus pada perubahan pada struktur tata letak secara keseluruhan. Dalam penyiapan multipanel, mengubah konten email di panel detail tidak akan mengubah struktur tata letak yang mendasarinya. Oleh karena itu, tombol kembali mungkin keluar dari aplikasi atau grafik navigasi saat ini karena tidak ada perubahan tata letak untuk dikembalikan dalam konteks saat ini. Dalam tata letak satu panel, menekan kembali akan melewati perubahan konten dalam tampilan detail dan kembali ke tampilan daftar, karena hal ini menunjukkan perubahan tata letak yang jelas.

Perhatikan contoh berikut:

  • Multi-Panel: Anda melihat email (Item 1) di panel detail. Mengklik email lain (Item 2) akan memperbarui panel detail, tetapi panel daftar dan detail tetap terlihat. Menekan kembali dapat keluar dari aplikasi atau alur navigasi saat ini.
  • Panel Tunggal: Anda melihat Item 1, lalu Item 2, menekan kembali akan mengarahkan Anda langsung ke panel daftar email.

Gunakan ini jika Anda ingin pengguna melihat transisi tata letak yang berbeda dengan setiap tindakan kembali.

Perubahan nilai navigasi.
PopUntilContentChange

Perilaku ini memprioritaskan konten yang ditampilkan. Jika Anda melihat Item 1, lalu Item 2, menekan kembali akan mengembalikan ke Item 1, terlepas dari tata letaknya.

Perhatikan contoh berikut:

  • Multi-Panel: Anda melihat Item 1 di panel detail, lalu mengklik Item 2 dalam daftar. Panel detail akan diperbarui. Menekan kembali akan memulihkan panel detail ke Item 1.
  • Satu Panel: Reversi konten yang sama akan terjadi.

Gunakan ini saat pengguna Anda mengharapkan untuk kembali ke konten yang dilihat sebelumnya dengan tindakan kembali.

transisi antara dua panel detail
PopUntilCurrentDestinationChange

Perilaku ini akan memunculkan data sebelumnya hingga tujuan navigasi saat ini berubah. Hal ini berlaku sama untuk tata letak satu dan multi-panel.

Perhatikan contoh berikut:

Terlepas dari apakah Anda berada dalam tata letak satu atau multi-panel, menekan kembali akan selalu memindahkan fokus dari elemen navigasi yang ditandai ke tujuan sebelumnya. Di aplikasi email kami, ini berarti indikasi visual panel yang dipilih akan bergeser.

Gunakan ini jika mempertahankan indikasi visual yang jelas tentang navigasi saat ini sangat penting untuk pengalaman pengguna.

beralih antara panel detail dan daftar
PopLatest

Opsi ini hanya menghapus tujuan terbaru dari data sebelumnya. Gunakan opsi ini untuk navigasi kembali tanpa melewati status perantara.

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

val scaffoldNavigator = rememberListDetailPaneScaffoldNavigator<MyItem>()
val scope = rememberCoroutineScope()

NavigableListDetailPaneScaffold(
    navigator = scaffoldNavigator,
    listPane = {
        AnimatedPane {
            MyList(
                onItemClick = { item ->
                    // Navigate to the detail pane with the passed item
                    scope.launch {
                        scaffoldNavigator.navigateTo(
                            ListDetailPaneScaffoldRole.Detail,
                            item
                        )
                    }
                },
            )
        }
    },
    detailPane = {
        AnimatedPane {
            // Show the detail pane content if selected item is available
            scaffoldNavigator.currentDestination?.contentKey?.let {
                MyDetails(it)
            }
        }
    },
)