التنقّل باستخدام العناصر المشترَكة

الشكل 1. التنقّل باستخدام العناصر المشترَكة

تساعد العناصر المشتركة في جعل عمليات الانتقال بين الشاشات أكثر سلاسة وجاذبية من خلال إنشاء رابط مرئي يوجّه المستخدم. يوضّح هذا الدليل كيفية استخدام واجهات برمجة التطبيقات للعناصر المشتركة مع مكتبتَي Navigation 3 وNavigation 2 في Jetpack.

يتضمّن المقتطف التالي الدالتَين المركّبتَين DetailsScreen وHomeScreen اللتين تُستخدمان كوجهتَين يمكن للمستخدمين التنقّل بينهما. في كل شاشة، يتم استخدام المُعدِّل sharedElement على كل من الصورة والنص بحيث يتم تحريك كل عنصر من هذه العناصر بشكل مستقل بين الشاشات.

@Composable
fun DetailsScreen(
    id: Int,
    snack: Snack,
    sharedTransitionScope: SharedTransitionScope,
    animatedVisibilityScope: AnimatedVisibilityScope,
    onBackPressed: () -> Unit
) {
    with(sharedTransitionScope) {
        Column(
            modifier = Modifier
                .fillMaxSize()
                .clickable { onBackPressed() },
        ) {
            Image(
                painterResource(id = snack.image),
                contentDescription = snack.description,
                contentScale = ContentScale.Crop,
                modifier = Modifier
                    .sharedElement(
                        sharedTransitionScope.rememberSharedContentState(key = "image-$id"),
                        animatedVisibilityScope = animatedVisibilityScope
                    )
                    .aspectRatio(1f)
                    .fillMaxWidth()
            )
            Text(
                text = snack.name,
                fontSize = 18.sp,
                modifier = Modifier
                    .sharedElement(
                        sharedTransitionScope.rememberSharedContentState(key = "text-$id"),
                        animatedVisibilityScope = animatedVisibilityScope
                    )
                    .fillMaxWidth(),
            )
        }
    }
}

@Composable
fun HomeScreen(
    sharedTransitionScope: SharedTransitionScope,
    animatedVisibilityScope: AnimatedVisibilityScope,
    onItemClick: (Int) -> Unit,
) {
    LazyColumn(
        modifier = Modifier
            .fillMaxSize()
            .padding(8.dp),
        verticalArrangement = Arrangement.spacedBy(8.dp)
    ) {
        itemsIndexed(listSnacks) { index, item ->
            Row(
                modifier = Modifier
                    .fillMaxWidth()
                    .clickable { onItemClick(index) },
            ) {
                Spacer(modifier = Modifier.width(8.dp))
                with(sharedTransitionScope) {
                    Image(
                        painterResource(id = item.image),
                        contentDescription = item.description,
                        contentScale = ContentScale.Crop,
                        modifier = Modifier
                            .sharedElement(
                                sharedTransitionScope.rememberSharedContentState(key = "image-$index"),
                                animatedVisibilityScope = animatedVisibilityScope
                            )
                            .size(100.dp)
                    )
                    Spacer(modifier = Modifier.width(8.dp))
                    Text(
                        item.name,
                        fontSize = 18.sp,
                        modifier = Modifier
                            .align(Alignment.CenterVertically)
                            .sharedElement(
                                sharedTransitionScope.rememberSharedContentState(key = "text-$index"),
                                animatedVisibilityScope = animatedVisibilityScope,
                            )
                    )
                }
            }
        }
    }
}

لاستخدام واجهات برمجة التطبيقات للعناصر المشتركة مع Navigation 3، عليك أولاً تضمين NavDisplay في تطبيقك في SharedTransitionLayout. يمكنك بعد ذلك تمرير SharedTransitionScope المقدَّم إلى الدوال المركّبة للشاشة.

بالنسبة إلى AnimatedVisibilityScope، استخدِم LocalNavAnimatedContentScope المحلية التي توفّر AnimatedContentScope من AnimatedContent التي يستخدمها NavDisplay داخليًا لإضافة تأثيرات متحركة بين المَشاهد.

@Composable
fun SharedElement_Nav3() {
    SharedTransitionLayout {
        val backStack = rememberNavBackStack(HomeRoute)

        // Note: NavDisplay accepts a `sharedTransitionScope` parameter, which is used to animate
        // NavEntry instances between scenes. This parameter *isn't* required for shared element
        // or shared bounds transitioning elements between different NavEntry, as demonstrated in
        // this sample.
        // See https://developer.android.com/guide/navigation/navigation-3/animate-destinations#transition-nav-entries
        NavDisplay(
            modifier = Modifier.safeDrawingPadding(),
            backStack = backStack,
            entryProvider = entryProvider {
                entry<HomeRoute> {
                    HomeScreen(
                        sharedTransitionScope = this@SharedTransitionLayout,
                        animatedVisibilityScope = LocalNavAnimatedContentScope.current,
                        onItemClick = { backStack.add(DetailsRoute(it)) })
                }
                entry<DetailsRoute> { detailsRoute ->
                    val id = detailsRoute.item
                    val snack = listSnacks[id]

                    DetailsScreen(
                        id = id,
                        snack = snack,
                        sharedTransitionScope = this@SharedTransitionLayout,
                        animatedVisibilityScope = LocalNavAnimatedContentScope.current,
                        onBackPressed = {
                            backStack.removeLastOrNull()
                        },
                    )
                }
            })
    }
}

لاستخدام واجهات برمجة التطبيقات للعناصر المشترَكة مع Navigation 2، عليك أولاً تضمين NavHost لتطبيقك في SharedTransitionLayout. يمكنك بعد ذلك تمرير SharedTransitionScope المقدَّم إلى الدوال المركّبة للشاشة.

تستخدم المَعلمة content لأداة إنشاء composable AnimatedContentScope كمستلِم، لذا يمكنك استخدام this@composable للإشارة إلى هذا النطاق.

@Composable
fun SharedElement_Nav2() {
    SharedTransitionLayout {
        val navController = rememberNavController()
        NavHost(
            navController = navController,
            startDestination = "home",
            modifier = Modifier.safeDrawingPadding()
        ) {
            composable("home") {
                HomeScreen(
                    sharedTransitionScope = this@SharedTransitionLayout,
                    animatedVisibilityScope = this@composable,
                    onItemClick = { navController.navigate("details/$it") })
            }
            composable(
                "details/{item}", arguments = listOf(navArgument("item") { type = NavType.IntType })
            ) { backStackEntry ->
                val id = backStackEntry.arguments?.getInt("item") ?: 0
                val snack = listSnacks[id]
                DetailsScreen(
                    id = id,
                    snack = snack,
                    sharedTransitionScope = this@SharedTransitionLayout,
                    animatedVisibilityScope = this@composable,
                    onBackPressed = {
                        navController.popBackStack()
                    }
                )
            }
        }
    }
}

إيماءة إظهار شاشة الرجوع مع العناصر المشترَكة

لاستخدام ميزة إيماءة إظهار شاشة الرجوع مع العناصر المشترَكة، اتّبِع الخطوات التالية:

  1. تتيح جميع إصدارات Navigation 3 ميزة "إيماءة إظهار شاشة الرجوع". بالنسبة إلى Navigation 2، استخدِم الإصدار 2.8.0 من navigation-compose أو إصدار أحدث:

    [versions]
    androidx-navigation = "2.8.0" # Or higher
    
    [libraries]
    androidx-navigation-compose = { module = "androidx.navigation:navigation-compose", version.ref = "androidx-navigation" }
    
    dependencies {
        implementation(libs.androidx.navigation.compose)
    }
    
  2. يتم تفعيل ميزة &quot;إيماءة إظهار شاشة الرجوع&quot; تلقائيًا على الأجهزة التي تعمل بالإصدار 15 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 35) أو الإصدارات الأحدث. بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android 14 (المستوى 34 لواجهة برمجة التطبيقات)، عليك تفعيل إعداد "إيماءة إظهار شاشة الرجوع" في خيارات المطوّرين.

  3. إذا كان تطبيقك يستهدف الإصدار 14 من نظام التشغيل Android أو الإصدارات الأقدم، يجب إضافة android:enableOnBackInvokedCallback="true" إلى <application> أو عناصر <activity> معيّنة في ملف AndroidManifest.xml. ولن تحتاج إلى هذه العلامة إذا كان تطبيقك يستهدف Android 15 أو الإصدارات الأحدث.

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
      <application
          ...
          android:enableOnBackInvokedCallback="true">
      </application>
    </manifest>
    
الشكل 2. العناصر المشترَكة مع ميزة "إيماءة إظهار شاشة الرجوع"