پویانمایی بین مقصدها

NavDisplay قابلیت‌های پویانمایی داخلی را برای ایجاد گذارهای بصری روان هنگام پیمایش کاربران در برنامه شما ارائه می‌دهد. می‌توانید این پویانمایی‌ها را به‌صورت سراسری برای NavDisplay یا در سطح Scene بااستفاده از فراداده سفارشی‌سازی کنید.

آشنایی با قابلیت‌های پویانمایی داخلی

NavDisplay از میانای برنامه‌سازی کاربردی ContentTransform برای تعریف نحوه پویانمایی محتوا درطول پیمایش استفاده می‌کند. NavDisplay به‌طور خودکار انتقال بین صحنه‌ها را وقتی کلید مشتق‌شده از کلاس صحنه فعلی و ویژگی key آن تغییر می‌کند، پویانمایی می‌کند. وقتی این کلید تغییر می‌کند، NavDisplay از ContentTransform برای نوع انتقال (جلو، عقب، یا عقب پیش‌بینانه) از صحنه مناسب در انتقال استفاده می‌کند. اگر ContentTransform تعریف نشده باشد، NavDisplay به استفاده از گذار پیش‌فرض مربوطه برمی‌گردد.

لغو انتقال‌های پیش‌فرض

می‌توانید با ارائه پارامترهای انتقال به NavDisplay، رفتارهای پویانمایی پیش‌فرض را لغو کنید.

  • transitionSpec: این پارامتر ContentTransform را برای اعمال شدن هنگام اضافه شدن محتوا به پشته قبلی‌ها (یعنی هنگام پیمایش روبه‌جلو) تعریف می‌کند.
  • popTransitionSpec: این پارامتر ContentTransform را برای اعمال شدن هنگام برداشته شدن محتوا از پشته قبلی‌ها (یعنی هنگام پیمایش به عقب) تعریف می‌کند.
  • predictivePopTransitionSpec: این پارامتر ContentTransform را برای اعمال شدن هنگام باز شدن محتوا بااستفاده از اشاره برگشت پیش‌گویانه تعریف می‌کند.

لغو انتقال‌ها در سطح Scene

می‌توانید از فراداده برای تعریف کردن پویانمایی‌های سفارشی برای صحنه‌های مجزا بااستفاده از کلیدهای فراداده زیر که توسط NavDisplay تعریف شده‌اند استفاده کنید:

درصورت ارائه، این انتقال‌های سطح صحنه به‌جای پیش‌فرض‌های مربوطه تنظیم‌شده در NavDisplay استفاده می‌شوند.

قطعه کد زیر هم انتقال‌های سراسری NavDisplay و هم لغو در سطح فردی NavEntry را نشان می‌دهد:

@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)
                )
            }
        }
    }
}

شکل ۱. برنامه با پویانمایی‌های سفارشی.

انتقال ورودی‌های پیمایش بین صحنه‌ها

در برنامه‌هایی که بااستفاده از صحنه‌ها چیدمان‌های سفارشی ایجاد می‌کنند، ممکن است NavEntry درطول انتقال در ویژگی entries هر دو صحنه گنجانده شود. به‌طور داخلی، NavDisplay تأیید می‌کند که هر ورودی در هر زمان حداکثر در یک صحنه نمایش داده می‌شود، که می‌تواند منجر به انتقال‌های پرشی شود وقتی صحنه رندرینگ NavEntry تغییر می‌کند. برای پویانمایی روان ورودی‌ها بین صحنه‌ها، می‌توانید NavDisplay خود را در یک SharedTransitionLayout بپیچید و SharedTransitionScope را به NavDisplay ارائه دهید، همان‌طور که در مثال زیر نشان داده شده است:

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

شکل ۲. Jumpy transition when not passing the SharedTransitionScope to NavDisplay.
شکل ۳. گذار روان هنگام عبور از SharedTransitionScope به NavDisplay.