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

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

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

‫NavDisplay از ContentTransform API برای تعریف نحوه پویانمایی محتوا درحین پیمایش استفاده می‌کند. وقتی کلیدی که از کلاس صحنه فعلی و ویژگی key آن مشتق شده است تغییر می‌کند، NavDisplay به‌طور خودکار گذار بین صحنه‌ها را پویانمایی می‌کند. وقتی این کلید تغییر می‌کند، 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
    )
}

شکل ۲. انتقال پرشی وقتی SharedTransitionScope به NavDisplay منتقل نمی‌شود.
شکل ۳. گذار روان هنگام انتقال SharedTransitionScope به NavDisplay.