Memahami dan menerapkan dasar-dasarnya

Navigasi menjelaskan cara pengguna berpindah-pindah di aplikasi Anda. Pengguna berinteraksi dengan elemen UI, biasanya dengan mengetuk atau mengkliknya, dan aplikasi merespons dengan menampilkan konten baru. Jika ingin kembali ke konten sebelumnya, pengguna dapat menggunakan gestur kembali atau mengetuk tombol kembali.

Membuat model status navigasi

Cara mudah untuk memodelkan perilaku ini adalah dengan tumpukan konten. Saat pengguna menavigasi maju ke konten baru, konten tersebut didorong ke bagian atas tumpukan. Saat pengguna kembali dari konten tersebut, konten akan dikeluarkan dari tumpukan dan konten sebelumnya akan ditampilkan. Dalam istilah navigasi, tumpukan ini biasanya disebut sebagai tumpukan kembali karena merepresentasikan konten yang dapat dikunjungi kembali oleh pengguna.

Tombol tindakan keyboard virtual (ikon tanda centang) yang dilingkari warna merah.
Gambar 1. Diagram yang menunjukkan cara perubahan stack kembali dengan peristiwa navigasi pengguna.

Membuat back stack

Di Navigasi 3, stack kembali tidak benar-benar berisi konten. Sebagai gantinya, referensi ke konten, yang dikenal sebagai kunci, disertakan. Kunci dapat berupa jenis apa pun, tetapi biasanya berupa class data serial yang sederhana. Penggunaan referensi, bukan konten, memiliki manfaat berikut:

  • Navigasi menjadi sederhana dengan mendorong tombol ke data sebelumnya.
  • Selama kunci dapat diserialisasi, data sebelumnya dapat disimpan ke penyimpanan persisten, sehingga dapat bertahan saat terjadi perubahan konfigurasi dan penghentian proses. Hal ini penting karena pengguna berharap untuk keluar dari aplikasi Anda, kembali ke aplikasi tersebut nanti, dan melanjutkan dari bagian yang mereka tinggalkan dengan konten yang sama yang ditampilkan. Lihat Menyimpan data sebelumnya untuk mengetahui informasi selengkapnya.

Konsep utama dalam Navigation 3 API adalah Anda memiliki data sebelumnya. Perpustakaan:

  • Mengharapkan bahwa tumpukan kembali Anda akan menjadi List<T> yang didukung status snapshot, dengan T adalah jenis tumpukan kembali keys. Anda dapat menggunakan Any atau Anda dapat memberikan kunci Anda sendiri yang memiliki jenis yang lebih kuat. Saat Anda melihat istilah "push" atau "pop", penerapan yang mendasarinya adalah menambahkan atau menghapus item dari akhir daftar.
  • Mengamati tumpukan kembali Anda dan mencerminkan statusnya di UI menggunakan NavDisplay.

Contoh berikut menunjukkan cara membuat kunci dan tumpukan kembali, serta mengubah tumpukan kembali sebagai respons terhadap peristiwa navigasi pengguna:

// Define keys that will identify content
data object ProductList
data class ProductDetail(val id: String)

@Composable
fun MyApp() {

    // Create a back stack, specifying the key the app should start with
    val backStack = remember { mutableStateListOf<Any>(ProductList) }

    // Supply your back stack to a NavDisplay so it can reflect changes in the UI
    // ...more on this below...

    // Push a key onto the back stack (navigate forward), the navigation library will reflect the change in state
    backStack.add(ProductDetail(id = "ABC"))

    // Pop a key off the back stack (navigate back), the navigation library will reflect the change in state
    backStack.removeLastOrNull()
}

Menyelesaikan kunci ke konten

Konten dimodelkan di Navigation 3 menggunakan NavEntry, yang merupakan class yang berisi fungsi composable. Tindakan ini merepresentasikan tujuan - satu bagian konten yang dapat digunakan pengguna untuk berpindah ke depan dan kembali dari.

NavEntry juga dapat berisi metadata - informasi tentang konten. Metadata ini dapat dibaca oleh objek penampung, seperti NavDisplay, untuk membantu objek tersebut memutuskan cara menampilkan konten NavEntry. Misalnya, metadata dapat digunakan untuk mengganti animasi default untuk NavEntry tertentu. NavEntry metadata adalah peta kunci String ke nilai Any, yang menyediakan penyimpanan data serbaguna.

Untuk mengonversi key menjadi NavEntry, buat Penyedia Entri. Ini adalah fungsi yang menerima key dan menampilkan NavEntry untuk key tersebut. Biasanya ditentukan sebagai parameter lambda saat membuat NavDisplay.

Ada dua cara untuk membuat Penyedia Entri, yaitu dengan membuat fungsi lambda secara langsung, atau dengan menggunakan DSL entryProvider.

Membuat fungsi Penyedia Entri secara langsung

Anda biasanya membuat fungsi Penyedia Entri menggunakan pernyataan when, dengan cabang untuk setiap kunci.

entryProvider = { key ->
    when (key) {
        is ProductList -> NavEntry(key) { Text("Product List") }
        is ProductDetail -> NavEntry(
            key,
            metadata = mapOf("extraDataKey" to "extraDataValue")
        ) { Text("Product ${key.id} ") }

        else -> {
            NavEntry(Unit) { Text(text = "Invalid Key: $it") }
        }
    }
}

Menggunakan DSL entryProvider

DSL entryProvider dapat menyederhanakan fungsi lambda Anda dengan menghindari kebutuhan untuk menguji setiap jenis kunci, dan membuat NavEntry untuk setiap jenis kunci. Gunakan fungsi builder entryProvider untuk melakukannya. Fungsi ini juga mencakup perilaku penggantian default (menampilkan error) jika kunci tidak ditemukan.

entryProvider = entryProvider {
    entry<ProductList> { Text("Product List") }
    entry<ProductDetail>(
        metadata = mapOf("extraDataKey" to "extraDataValue")
    ) { key -> Text("Product ${key.id} ") }
}

Perhatikan hal berikut dari cuplikan:

  • entry digunakan untuk menentukan NavEntry dengan jenis dan konten composable tertentu
  • entry menerima parameter metadata untuk menyetel NavEntry.metadata

Menampilkan data sebelumnya

Back stack mewakili status navigasi aplikasi Anda. Setiap kali back stack berubah, UI aplikasi harus mencerminkan status back stack baru. Di Navigation 3, NavDisplay mengamati data sebelumnya dan mengupdate UI-nya. Buat dengan parameter berikut:

  • Tumpukan kembali Anda - ini harus berjenis SnapshotStateList<T>, dengan T adalah jenis kunci tumpukan kembali Anda. Ini adalah List yang dapat diamati sehingga memicu rekomposisi NavDisplay saat berubah.
  • entryProvider untuk mengonversi kunci di tumpukan kembali Anda menjadi objek NavEntry.
  • Jika ingin, berikan lambda ke parameter onBack. Metode ini dipanggil saat pengguna memicu peristiwa kembali.

Contoh berikut menunjukkan cara membuat NavDisplay.

data object Home
data class Product(val id: String)

@Composable
fun NavExample() {

    val backStack = remember { mutableStateListOf<Any>(Home) }

    NavDisplay(
        backStack = backStack,
        onBack = { backStack.removeLastOrNull() },
        entryProvider = { key ->
            when (key) {
                is Home -> NavEntry(key) {
                    ContentGreen("Welcome to Nav3") {
                        Button(onClick = {
                            backStack.add(Product("123"))
                        }) {
                            Text("Click to navigate")
                        }
                    }
                }

                is Product -> NavEntry(key) {
                    ContentBlue("Product ${key.id} ")
                }

                else -> NavEntry(Unit) { Text("Unknown route") }
            }
        }
    )
}

Secara default, NavDisplay menampilkan NavEntry teratas di data sebelumnya dalam tata letak panel tunggal. Rekaman berikut menunjukkan aplikasi ini sedang berjalan:

Perilaku default `NavDisplay` dengan dua tujuan.
Gambar 2. Perilaku default NavDisplay dengan dua tujuan.

Siklus proses tujuan

NavDisplay menggunakan LifecycleOwner kustom untuk membatasi status siklus proses NavEntry berdasarkan batasan tingkat Scene dan batasan tingkat Entri.

Untuk mengetahui informasi selengkapnya tentang siklus proses di Compose, lihat Siklus Proses di Jetpack Compose.

Batasan siklus proses tingkat adegan

NavDisplay mengelola siklus proses Scene aktif. Batas tingkat adegan ditentukan sebagai berikut:

Untuk adegan non-overlay:

  • RESUMED: Hanya diizinkan saat transisi adegan telah selesai dan tidak ada adegan overlay aktif yang ditampilkan di atasnya.
  • STARTED: Dibatasi pada STARTED saat transisi adegan, seperti saat bernavigasi maju atau mundur, atau saat ditutupi oleh overlay.

Untuk adegan overlay, seperti dialog atau sheet bawah:

  • RESUMED: Hanya diizinkan untuk adegan overlay paling atas yang saat ini aktif.
  • STARTED: Dibatasi pada STARTED untuk setiap adegan overlay pokok yang dicakup oleh overlay yang lebih baru.

Status siklus proses tingkat entri

Library mengelola status siklus proses maksimum setiap NavEntry berdasarkan keberadaannya di stack belakang:

  • RESUMED: Jika entri ada di stack kembali saat ini, siklus prosesnya dapat mencapai RESUMED (tunduk pada batas tingkat adegan).
  • CREATED: Jika entri tidak lagi berada di stack belakang, seperti saat entri dikeluarkan dari stack, tetapi masih dirender di layar saat animasi keluar, library akan membatasi siklus prosesnya secara ketat di CREATED. Batas ini memastikan bahwa entri latar belakang atau keluar berhenti menjalankan pekerjaan aktif seperti mengumpulkan alur atau meluncurkan coroutine yang terikat ke status RESUMED atau STARTED saat menyelesaikan transisi keluar.

Cara menggabungkannya

Misalnya, status siklus proses akhir NavEntry diselesaikan sebagai berikut:

Skenario Batas Tingkat Adegan Batas Tingkat Pemula Batas Efektif
Entri aktif, layar yang diselesaikan (tanpa transisi atau overlay) RESUMED RESUMED RESUMED
Entri aktif, selama transisi (beralih ke atau dari) STARTED RESUMED STARTED
Entri aktif, yang ditutupi oleh overlay (misalnya, Dialog terbuka) STARTED RESUMED STARTED
Entri yang muncul, animasi keluar STARTED atau RESUMED CREATED CREATED

Menggabungkan semuanya

Diagram berikut menunjukkan cara alur data di antara berbagai objek di Navigation 3:

Visualisasi alur data antara berbagai objek di Navigation 3.
Gambar 3. Diagram yang menunjukkan cara data mengalir melalui berbagai objek di Navigation 3.
  1. Peristiwa navigasi memulai perubahan. Kunci ditambahkan atau dihapus dari tumpukan kembali sebagai respons terhadap interaksi pengguna.

  2. Perubahan pada status stack kembali memicu pengambilan konten. NavDisplay (composable yang merender data sebelumnya) mengamati data sebelumnya. Dalam konfigurasi default-nya, komponen ini menampilkan entri data sebelumnya teratas dalam tata letak satu panel. Saat tombol teratas di back stack berubah, NavDisplay menggunakan tombol ini untuk meminta konten yang sesuai dari penyedia entri.

  3. Penyedia entri menyediakan konten. Penyedia entri adalah fungsi yang menyelesaikan kunci ke NavEntry. Setelah menerima kunci dari NavDisplay, penyedia entri memberikan NavEntry terkait, yang berisi kunci dan konten.

  4. Konten ditampilkan. NavDisplay menerima NavEntry dan menampilkan konten.