التنقل والحزمة الخلفية

تحتوي "NavController" على "حزمة خلفية". يحتوي على الوجهات التي يستعملها المستخدم زاره بنفسك. وأثناء انتقال المستخدم إلى الشاشات في جميع أنحاء تطبيقك، يضيف NavController الوجهات من وإلى الحزمة الخلفية ويزيلها.

فيما تكون الحزمة الخلفية هي "الأولى في المكدس" بنية البيانات. تشير رسالة الأشكال البيانية يدفع NavController العناصر إلى العناصر وينبثق بها من أعلى حزمة.

السلوك الأساسي

في ما يلي الحقائق الأساسية التي يجب مراعاتها فيما يتعلق بسلوك الجهة الخلفية المكدس:

  • الوجهة الأولى: عندما يفتح المستخدم التطبيق، يتم عرض NavController ينقل الوجهة الأولى إلى أعلى الحزمة الخلفية.
  • جارٍ الإرسال إلى الحزمة: كل مكالمة NavController.navigate() يتم دفعها الوجهة المحددة إلى أعلى الحزمة.
  • تمييز الوجهة العليا: يؤدي النقر على السهم المتّجه للأعلى أو رجوع إلى استدعاء NavController.navigateUp() وNavController.popBackStack() على التوالي. هم يفصلون الوجهة العليا عن الحزمة. يمكنك الاطّلاع على صفحة مبادئ التنقل لمزيد من المعلومات حول الفارق بين للأعلى ورجوع.

رجوع

تحاول الطريقة NavController.popBackStack() عرض الصفحة الحالية خارج الحزمة الخلفية والانتقال إلى الوجهة السابقة. هذا النمط يؤدي إلى نقل المستخدم إلى الخلف خطوة واحدة بشكل فعال في سجل التنقل الخاص به. يقوم بإرجاع قيمة منطقية تشير إلى ما إذا كانت قد عادت بنجاح إلى الوجهة.

العودة إلى وجهة معيّنة

ويمكنك أيضًا استخدام popBackStack() للانتقال إلى وجهة معيّنة. للقيام بذلك، لذلك، استخدم أحد أحمالها. هناك العديد من الطرق التي تسمح لك بالمرور مثل عدد صحيح id أو سلسلة route. تستغرق هذه الأحمال الزائدة المستخدِم إلى الوجهة المرتبطة بالمعرّف المحدّد. الأهم من ذلك، يفسد كل شيء على الحزمة فوق تلك الوجهة.

تستخدم عمليات التحميل الزائدة هذه أيضًا قيمة منطقية inclusive. إنه يحدد ما إذا كان يجب أن ينفصل NavController أيضًا الوجهة المحددة عن الحزمة الخلفية بعد الانتقال إليه.

إليك هذا المقتطف الموجز كمثال:

navController.popBackStack(R.id.destinationId, true)

هنا، يعود NavController إلى الوجهة مع رقم التعريف الصحيح destinationId بما أن قيمة الوسيطة inclusive هي true، تؤدي NavController أيضًا إلى عرض الوجهة المحدّدة من الحزمة الخلفية.

التعامل مع رسالة منبثقة فاشلة

عندما تعرض popBackStack() القيمة false، استدعاء لاحق إلى تُرجع NavController.getCurrentDestination() null. هذا يعني أن التطبيق يحتوي على قامت بتمييز الوجهة الأخيرة من المكدس الخلفي. في هذه الحالة، يرى المستخدم فقط شاشة فارغة.

يمكن أن يحدث هذا في الحالات التالية:

  • لم ينشر "popBackStack()" أي عنصر من الحزمة.
  • تم حذف وجهة من الحزمة الخلفية من قِبَل "popBackStack()" وأصبحت فارغ الآن.

لحلّ هذه المشكلة، عليك الانتقال إلى وجهة جديدة أو الاتصال برقم finish(). على نشاطك لإنهائه. ويوضّح المقتطف التالي هذا:

كوتلين

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

جافا

...

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish();
}

الانبثاق إلى وجهة

لإزالة وجهات من الحزمة الخلفية عند التنقّل من وجهة واحدة إلى دالة أخرى، أضِف وسيطة popUpTo() إلى الدالة navigate() المرتبطة. الاتصال. توجه popUpTo() مكتبة التنقل لإزالة بعض الوجهات من الحزمة الخلفية كجزء من المكالمة إلى navigate(). قيمة المعلمة هي معرّف الوجهة في الحزمة الخلفية. يمكن أن يكون المعرف العدد الصحيح id أو السلسلة route.

يمكنك تضمين وسيطة للمَعلمة inclusive بقيمة true. للإشارة إلى أن الوجهة التي حددتها في popUpTo() يجب أن تكون أيضًا المكدس الخلفي المنبثق.

لتنفيذ هذه العملية آليًا، يُرجى تمرير popUpTo() إلى navigate() كجزء من NavOptions مع ضبط inclusive على true. يعمل هذا في كل من Compose مرّات المشاهدة.

حفظ الحالة عند ظهور نافذة منبثقة

عند استخدام popUpTo للانتقال إلى وجهة ما، يمكنك حفظ وظهرت حالات جميع الوجهات من المكدس الخلفي. يمكنك ثم استعادة حزمة الخلفية والوجهات عند الانتقال إلى تلك الوجهة في وقت لاحق. يتيح لك ذلك الحفاظ على الحالة لوجهة معيّنة عدة حزم خلفية.

لإجراء ذلك آليًا، يمكنك تحديد saveState = true عند إضافة popUpTo إلى خيارات التنقل.

يمكنك أيضًا تحديد restoreState = true في خيارات التنقّل من أجل: استعادة الحزمة الخلفية والحالة المرتبطة الوجهة.

مثلاً:

navController.navigate(
    route = route,
    navOptions =  navOptions {
        popUpTo<A>{ saveState = true }
        restoreState = true
    }
)

لتفعيل حفظ الحالة واستعادتها في ملف XML، يجب تحديد popUpToSaveState على أنّه true. وrestoreState في شكل true على التوالي في action المرتبطة.

مثال على تنسيق XML

إليك مثال على popUpTo بتنسيق XML باستخدام إجراء:

<action
  android:id="@+id/action_a_to_b"
  app:destination="@id/b"
  app:popUpTo="@+id/a"
  app:popUpToInclusive="true"
  app:restoreState=”true”
  app:popUpToSaveState="true"/>

مثال على الإنشاء

المثال التالي هو مثال كامل لشيء واحد في Compose:

@Composable
fun MyAppNavHost(
    modifier: Modifier = Modifier,
    navController: NavHostController = rememberNavController(),
    startDestination: Any = A
) {
    NavHost(
        modifier = modifier,
        navController = navController,
        startDestination = startDestination
    ) {
        composable<A> {
            DestinationA(
                onNavigateToB = {
                // Pop everything up to, and including, the A destination off
                // the back stack, saving the back stack and the state of its
                // destinations.
                // Then restore any previous back stack state associated with
                // the B destination.
                // Finally navigate to the B destination.
                    navController.navigate(route = B) {
                        popUpTo<A> {
                            inclusive = true
                            saveState = true
                        }
                        restoreState = true
                    }
                },
            )
        }
        composable<B> { DestinationB(/* ... */) }
    }
}

@Composable
fun DestinationA(onNavigateToB: () -> Unit) {
    Button(onClick = onNavigateToB) {
        Text("Go to A")
    }
}

بشكل أكثر دقة، يمكنك تغيير طريقة الاتصال بـ NavController.navigate() في الطرق التالية:

// Pop everything up to the destination_a destination off the back stack before
// navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a")
}

// Pop everything up to and including the "destination_a" destination off
// the back stack before navigating to the "destination_b" destination
navController.navigate("destination_b") {
    popUpTo("destination_a") { inclusive = true }
}

// Navigate to the "search” destination only if we’re not already on
// the "search" destination, avoiding multiple copies on the top of the
// back stack
navController.navigate("search") {
    launchSingleTop = true
}

للحصول على معلومات عامة حول تمرير الخيارات إلى NavController.navigate()، يمكنك الاطّلاع على دليل التنقّل باستخدام الخيارات.

استخدام إجراءات مميزة

عند التنقّل باستخدام إجراء ما، يمكنك اختياريًا تمييز وجهات إضافية عن المكدس الخلفي. فعلى سبيل المثال، إذا كان تطبيقك يتضمن تدفق تسجيل الدخول الأولي، مرة واحدة أن يكون المستخدم قد سجّل الدخول، فيجب عليك إزالة جميع الوجهات المتعلقة بتسجيل الدخول حتى لا يعيد زر "رجوع" المستخدمين إلى تسجيل الدخول التدفق.

القراءة الإضافية

لمزيد من المعلومات، يُرجى الاطّلاع على الصفحات التالية:

  • التنقل الدائري: تعرّف على كيفية تجنُّب ازدحام الظهر. مكدس في الحالات التي تكون فيها تدفقات التنقل دائرية.
  • وجهات مربّعات الحوار: يمكنك الاطّلاع على كيفية تقديم وجهات مربّعات الحوار اعتبارات فريدة حول كيفية إدارة حزمة الظهر.