Menganimasikan transisi antar-tujuan

NavDisplay menyediakan kemampuan animasi bawaan untuk membuat transisi visual yang lancar saat pengguna menjelajahi aplikasi Anda. Anda dapat menyesuaikan animasi ini secara global untuk NavDisplay atau di tingkat Scene menggunakan metadata.

Memahami kemampuan animasi bawaan

NavDisplay menggunakan ContentTransform API untuk menentukan cara konten dianimasikan selama navigasi. NavDisplay secara otomatis menganimasikan transisi antar-adegan saat kunci yang berasal dari class adegan saat ini dan properti key-nya berubah. Saat kunci ini berubah, NavDisplay menggunakan ContentTransform untuk jenis transisi—maju, mundur, atau kembali prediktif—dari adegan yang sesuai dalam transisi. Jika ContentTransform tidak ditentukan, NavDisplay akan kembali menggunakan transisi default yang sesuai.

Mengganti transisi default

Anda dapat mengganti perilaku animasi default dengan memberikan parameter transisi ke NavDisplay.

  • transitionSpec: Parameter ini menentukan ContentTransform yang akan diterapkan saat konten ditambahkan ke data sebelumnya (yaitu, saat menavigasi ke depan).
  • popTransitionSpec: Parameter ini menentukan ContentTransform yang akan diterapkan saat konten dihapus dari data sebelumnya (yaitu, saat kembali).
  • predictivePopTransitionSpec: Parameter ini menentukan ContentTransform yang akan diterapkan saat konten dikeluarkan menggunakan gestur kembali prediktif.

Mengganti transisi di tingkat Scene

Anda dapat menggunakan metadata untuk menentukan animasi kustom untuk setiap adegan menggunakan kunci metadata berikut yang ditentukan oleh NavDisplay:

Jika disediakan, transisi tingkat adegan ini akan digunakan, bukan default yang sesuai yang ditetapkan di NavDisplay.

Cuplikan berikut menunjukkan transisi NavDisplay global dan penggantian di tingkat NavEntry individual:

@Serializable
data object ScreenA : NavKey

@Serializable
data object ScreenB : NavKey

@Serializable
data object ScreenC : NavKey

class AnimatedNavDisplayActivity : ComponentActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {

            Scaffold { paddingValues ->

                val backStack = rememberNavBackStack(ScreenA)

                NavDisplay(
                    backStack = backStack,
                    onBack = { backStack.removeLastOrNull() },
                    entryProvider = entryProvider {
                        entry<ScreenA> {
                            ContentOrange("This is Screen A") {
                                Button(onClick = { backStack.add(ScreenB) }) {
                                    Text("Go to Screen B")
                                }
                            }
                        }
                        entry<ScreenB> {
                            ContentMauve("This is Screen B") {
                                Button(onClick = { backStack.add(ScreenC) }) {
                                    Text("Go to Screen C")
                                }
                            }
                        }
                        entry<ScreenC>(
                            metadata = metadata {
                                put(NavDisplay.TransitionKey) {
                                    // Slide new content up, keeping the old content in place underneath
                                    slideInVertically(
                                        initialOffsetY = { it },
                                        animationSpec = tween(1000)
                                    ) togetherWith ExitTransition.KeepUntilTransitionsFinished
                                }
                                put(NavDisplay.PopTransitionKey) {
                                    // Slide old content down, revealing the new content in place underneath
                                    EnterTransition.None togetherWith
                                            slideOutVertically(
                                                targetOffsetY = { it },
                                                animationSpec = tween(1000)
                                            )
                                }
                                put(NavDisplay.PredictivePopTransitionKey) {
                                    // Slide old content down, revealing the new content in place underneath
                                    EnterTransition.None togetherWith
                                            slideOutVertically(
                                                targetOffsetY = { it },
                                                animationSpec = tween(1000)
                                            )
                                }
                            }
                        ) {
                            ContentGreen("This is Screen C")
                        }
                    },
                    transitionSpec = {
                        // Slide in from right when navigating forward
                        slideInHorizontally(initialOffsetX = { it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { -it })
                    },
                    popTransitionSpec = {
                        // Slide in from left when navigating back
                        slideInHorizontally(initialOffsetX = { -it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { it })
                    },
                    predictivePopTransitionSpec = {
                        // Slide in from left when navigating back
                        slideInHorizontally(initialOffsetX = { -it }) togetherWith
                            slideOutHorizontally(targetOffsetX = { it })
                    },
                    modifier = Modifier.padding(paddingValues)
                )
            }
        }
    }
}

Gambar 1. Aplikasi dengan animasi kustom.

Menyertakan entri nav transisi antar-adegan

Di aplikasi yang membuat tata letak kustom menggunakan adegan, NavEntry dapat disertakan dalam properti entries dari kedua adegan selama transisi. Secara internal, NavDisplay memverifikasi bahwa setiap entri ditampilkan dalam paling banyak satu adegan kapan saja, yang dapat menghasilkan transisi yang tersendat saat adegan yang merender NavEntry berubah. Untuk menganimasikan entri dengan lancar di antara adegan, Anda dapat menggabungkan NavDisplay dalam SharedTransitionLayout dan memberikan SharedTransitionScope ke NavDisplay seperti yang ditunjukkan dalam contoh berikut:

SharedTransitionLayout {
    NavDisplay(
        // ...
        sharedTransitionScope = this
    )
}