إضافة تأثيرات متحركة بين الوجهات

توفّر 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)
                )
            }
        }
    }
}

الشكل 1. تطبيق يتضمّن صورًا متحركة مخصّصة

نقل إدخالات شريط التنقّل بين المشاهد

في التطبيقات التي تنشئ تخطيطات مخصّصة باستخدام المشاهد، من المحتمل أن يتم تضمين NavEntry في السمة entries لكلتا المشهدين أثناء الانتقال. تتحقّق NavDisplay داخليًا من أنّ كل إدخال معروض في مشهد واحد على الأكثر في أي وقت، ما قد يؤدي إلى انتقالات متقطّعة عند تغيير المشهد الذي يعرض NavEntry. لتحريك العناصر بسلاسة بين المشاهد، يمكنك تضمين NavDisplay في SharedTransitionLayout وتوفير SharedTransitionScope إلى NavDisplay كما هو موضّح في المثال التالي:

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