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 API ContentTransform untuk menentukan cara konten dianimasikan selama navigasi. NavDisplay otomatis menganimasikan transisi antar-scene saat kunci yang berasal dari class scene saat ini dan properti key-nya berubah. Saat kunci ini berubah, NavDisplay akan menggunakan ContentTransform untuk jenis transisi—maju, mundur, atau kembali prediktif—dari scene yang sesuai dalam transisi. Jika ContentTransform tersebut 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 menavigasi kembali).
  • predictivePopTransitionSpec: Parameter ini menentukan ContentTransform yang akan diterapkan saat konten ditampilkan menggunakan gestur kembali prediktif.

Mengganti transisi di tingkat Scene

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

Jika disediakan, transisi tingkat scene 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.

Transisi entri navigasi antar-adegan

Dalam aplikasi yang membuat tata letak kustom menggunakan scene, NavEntry dapat disertakan dalam properti entries kedua scene selama transisi. Secara internal, NavDisplay memverifikasi bahwa setiap entri ditampilkan di maksimal satu scene pada satu waktu, yang dapat menyebabkan transisi yang tidak stabil saat scene yang merender NavEntry berubah. Untuk menganimasikan entri antar-adegan dengan lancar, Anda dapat menggabungkan NavDisplay dalam SharedTransitionLayout dan memberikan SharedTransitionScope ke NavDisplay seperti yang ditunjukkan dalam contoh berikut:

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

Gambar 2. Transisi yang tidak mulus saat tidak meneruskan SharedTransitionScope ke NavDisplay.
Gambar 3. Transisi yang lancar saat meneruskan SharedTransitionScope ke NavDisplay.