Membuat tata letak daftar-detail

Daftar-detail adalah pola UI yang terdiri dari tata letak panel ganda di mana satu panel menampilkan daftar item dan panel lainnya 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 menjadi daftar kategori dengan preferensi untuk setiap kategori di panel detail.

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

Menerapkan Pola Daftar-Detail dengan NavigableListDetailPaneScaffold

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

Struktur 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 menyesuaikan berdasarkan ukuran jendela:

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

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
  • adaptive-layout: Tata letak adaptif seperti ListDetailPaneScaffold dan SupportingPaneScaffold
  • adaptive-navigation: Composable untuk menavigasi dalam dan antar-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 mengaktifkan, tambahkan android:enableOnBackInvokedCallback="true" ke tag <application> atau tag <activity> individual dalam file AndroidManifest.xml Anda. Untuk mengetahui informasi selengkapnya, lihat Memilih untuk menggunakan gestur kembali prediktif.

Setelah aplikasi Anda menargetkan Android 16 (level API 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 antara panel daftar, detail, dan tambahan. Dengan mendeklarasikan jenis generik, navigator juga melacak status scaffold (yaitu, MyItem mana yang sedang ditampilkan). Karena jenis ini dapat di-parcel, 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 memiliki jenis yang sama dengan yang ditentukan dalam panggilan asli sehingga Anda dapat mengakses data apa pun yang perlu ditampilkan.

  1. Jika ingin, 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 detail di panel lainnya.

Perilaku ini berfokus pada perubahan pada struktur tata letak keseluruhan. Dalam penyiapan multi-panel, mengubah konten email di panel detail tidak akan mengubah struktur tata letak yang mendasarinya. Oleh karena itu, tombol kembali dapat membawa Anda keluar dari aplikasi atau grafik navigasi saat ini karena tidak ada perubahan tata letak yang dapat 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 tindakan ini menunjukkan perubahan tata letak yang jelas.

Perhatikan contoh berikut:

  • Multi-Panel: Anda sedang 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 mengembalikan 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 kembali ke Item 1, terlepas dari tata letaknya.

Perhatikan contoh berikut:

  • Multi-Panel: Anda melihat Item 1 di panel detail, lalu mengklik Item 2 di daftar. Panel detail diperbarui. Menekan tombol kembali akan memulihkan panel detail ke Item 1.
  • Panel Tunggal: Konten yang sama akan dikembalikan ke versi sebelumnya.

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

transisi antara dua panel detail
PopUntilCurrentDestinationChange

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

Perhatikan contoh berikut:

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

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

berpindah antara panel detail dan daftar
PopLatest

Opsi ini hanya menghapus tujuan terbaru dari backstack. 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)
            }
        }
    },
)