الرسومات البيانية المدمَجة

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

بالإضافة إلى ذلك، يمكن إعادة استخدام الرسوم البيانية المُدمجة. وتوفّر هذه الرسوم أيضًا مستوى من التضمين، إذ لا يمكن للوجهات خارج الرسم البياني المُدمَج الوصول مباشرةً إلى أيّ من الوجهات ضمن الرسم البياني المُدمَج. بدلاً من ذلك، يجب أن يتم navigate() إلى الرسم البياني المُدمَج نفسه، حيث يمكن أن يتغيّر المنطق الداخلي بدون التأثير في بقية الرسم البياني.

مثال

يجب أن يبدأ الرسم البياني للتنقّل في أعلى مستوى في تطبيقك بالوجهة المبدئية التي يراها المستخدم عند تشغيل التطبيق، ويجب أن يتضمّن الوجهات التي تظهر له أثناء تنقّله في تطبيقك.

الشكل 1. رسم بياني للتنقل على مستوى أعلى

باستخدام الرسم البياني للتنقّل على مستوى أعلى من الشكل 1، لنفترض أنّك أردت أن تطلب من المستخدم الاطّلاع على الشاشتَين title_screen وregister فقط عند تشغيل التطبيق للمرّة الأولى. بعد ذلك، يتم تخزين معلومات المستخدم، وعند تشغيل التطبيق لاحقًا، يجب توجيهه مباشرةً إلى شاشة المطابقة.

من أفضل الممارسات ضبط شاشة المطابقة على أنّها وجهة البداية لرسم بياني تنقّل في المستوى الأعلى، ونقل شاشتَي العنوان والتسجيل إلى رسم بياني ملفّق، كما هو موضّح في الشكل 1:

الشكل 2. يحتوي الآن الرسم البياني للتنقّل من المستوى الأعلى على رسم بياني مُدمَج.

عند تشغيل شاشة المطابقة، تحقّق ممّا إذا كان هناك مستخدم مسجَّل. إذا لم يكن المستخدم مسجّلاً، انتقِل به إلى شاشة التسجيل.

لمزيد من المعلومات عن سيناريوهات التنقّل الشَرطي، يُرجى الاطّلاع على مقالة التنقّل الشَرطي.

إنشاء

لإنشاء رسم بياني متداخل للتنقّل باستخدام Compose، استخدِم الدالة NavGraphBuilder.navigation(). يمكنك استخدام navigation() تمامًا مثل الدوالّ NavGraphBuilder.composable() وNavGraphBuilder.dialog() عند إضافة وجهات إلى رسم بياني.

والفرق الرئيسي بينهما هو أنّ navigation تنشئ رسمًا بيانيًا متداخلًا بدلاً من وجهة جديدة. بعد ذلك، يمكنك استدعاء composable() وdialog() ضمن دالة lambda في navigation() لإضافة وجهات إلى الرسم البياني المُدمَج.

راجِع كيفية تنفيذ المقتطف التالي للرسم البياني في الشكل 2 باستخدام Compose:

// Routes
@Serializable object Title
@Serializable object Register

// Route for nested graph
@Serializable object Game

// Routes inside nested graph
@Serializable object Match
@Serializable object InGame
@Serializable object ResultsWinner
@Serializable object GameOver

NavHost(navController, startDestination = Title) {
   composable<Title> {
       TitleScreen(
           onPlayClicked = { navController.navigate(route = Register) },
           onLeaderboardsClicked = { /* Navigate to leaderboards */ }
       )
   }
   composable<Register> {
       RegisterScreen(
           onSignUpComplete = { navController.navigate(route = Game) }
       )
   }
   navigation<Game>(startDestination = Match) {
       composable<Match> {
           MatchScreen(
               onStartGame = { navController.navigate(route = InGame) }
           )
       }
       composable<InGame> {
           InGameScreen(
               onGameWin = { navController.navigate(route = ResultsWinner) },
               onGameLose = { navController.navigate(route = GameOver) }
           )
       }
       composable<ResultsWinner> {
           ResultsWinnerScreen(
               onNextMatchClicked = {
                   navController.navigate(route = Match) {
                       popUpTo(route = Match) { inclusive = true }
                   }
               },
               onLeaderboardsClicked = { /* Navigate to leaderboards */ }
           )
       }
       composable<GameOver> {
           GameOverScreen(
               onTryAgainClicked = {
                   navController.navigate(route = Match) {
                       popUpTo(route = Match) { inclusive = true }
                   }
               }
           )
       }
   }
}

للانتقال مباشرةً إلى وجهة مُدمجة، استخدِم نوع مسار كما تفعل مع أي وجهة أخرى. ويرجع ذلك إلى أنّ المسارات هي مفهوم عام يُستخدَم لتحديد الوجهات التي يمكن لأي شاشة الانتقال إليها:

navController.navigate(route = Match)
.

XML

عند استخدام ملف XML، يمكنك استخدام "أداة تعديل التنقّل" لإنشاء الرسم البياني المُدمَج. اتّبِع الخطوات التالية لإجراء ذلك:

  1. في "أداة تعديل التنقّل"، اضغط مع الاستمرار على مفتاح Shift، ثم انقر على الوجهات التي تريد تضمينها في الرسم البياني المُدمَج.
  2. انقر بزر الماوس الأيمن لفتح قائمة السياقات، واختَر نقل إلى رسم بياني متداخل > رسم بياني جديد. تكون الوجهات محصورة في رسم بياني متداخل. يعرض الشكل 2 رسمًا بيانيًا متداخلًا في أداة تعديل التنقّل:

    الشكل 2. رسم بياني مُدمَج في "أداة التنقّل"
  3. انقر على الرسم البياني المُدمَج. تظهر السمات التالية في لوحة السمات:

    • النوع الذي يحتوي على "الرسم البياني المُدمَج"
    • رقم التعريف الذي يحتوي على رقم تعريف منسوب إلى النظام للرسم البياني المُدمَج. يُستخدَم هذا المعرّف للإشارة إلى الرسم البياني المُدمَج من الرمز البرمجي.
  4. انقر مرّتين على الرسم البياني المُدمَج لعرض وجهاته.

  5. انقر على علامة التبويب نص للتبديل إلى عرض XML. تمت إضافة رسم بياني متداخل للتنقّل إلى الرسم البياني. يحتوي مخطّط التنقّل هذا على عناصر navigation بالإضافة إلى معرّف خاص به وسمة startDestination تشير إلى الوجهة الأولى في المخطّط المُدمَج:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:app="http://schemas.android.com/apk/res-auto"
       xmlns:tools="http://schemas.android.com/tools"
       xmlns:android="http://schemas.android.com/apk/res/android"
       app:startDestination="@id/mainFragment">
       <fragment
           android:id="@+id/mainFragment"
           android:name="com.example.cashdog.cashdog.MainFragment"
           android:label="fragment_main"
           tools:layout="@layout/fragment_main" >
           <action
               android:id="@+id/action_mainFragment_to_sendMoneyGraph"
               app:destination="@id/sendMoneyGraph" />
           <action
               android:id="@+id/action_mainFragment_to_viewBalanceFragment"
               app:destination="@id/viewBalanceFragment" />
       </fragment>
       <fragment
           android:id="@+id/viewBalanceFragment"
           android:name="com.example.cashdog.cashdog.ViewBalanceFragment"
           android:label="fragment_view_balance"
           tools:layout="@layout/fragment_view_balance" />
       <navigation android:id="@+id/sendMoneyGraph" app:startDestination="@id/chooseRecipient">
           <fragment
               android:id="@+id/chooseRecipient"
               android:name="com.example.cashdog.cashdog.ChooseRecipient"
               android:label="fragment_choose_recipient"
               tools:layout="@layout/fragment_choose_recipient">
               <action
                   android:id="@+id/action_chooseRecipient_to_chooseAmountFragment"
                   app:destination="@id/chooseAmountFragment" />
           </fragment>
           <fragment
               android:id="@+id/chooseAmountFragment"
               android:name="com.example.cashdog.cashdog.ChooseAmountFragment"
               android:label="fragment_choose_amount"
               tools:layout="@layout/fragment_choose_amount" />
       </navigation>
    </navigation>
    
  6. في الرمز البرمجي، نقْل رقم تعريف المورد الخاص بالإجراء الذي يربط الرسم البياني الجذر بالرسم البياني المُدمَج:

Kotlin

view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)

Java

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. في علامة التبويب التصميم، ارجع إلى الرسم البياني الجذر بالنقر على الجذر.

الإشارة إلى الرسوم البيانية الأخرى للتنقّل باستخدام include

هناك طريقة أخرى لتقسيم بنية الرسم البياني إلى وحدات وهي تضمين رسم بياني واحد في رسم بياني آخر باستخدام عنصر <include> في الرسم البياني الرئيسي للتنقّل. يتيح ذلك تحديد الرسم البياني المضمّن في وحدة أو مشروع منفصلين بالكامل، ما يزيد من إمكانية إعادة الاستخدام إلى أقصى حد.

يوضّح المقتطف التالي كيفية استخدام <include>:

<!-- (root) nav_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/fragment">

    <strong><include app:graph="@navigation/included_graph" /></strong>

    <fragment
        android:id="@+id/fragment"
        android:name="com.example.myapplication.BlankFragment"
        android:label="Fragment in Root Graph"
        tools:layout="@layout/fragment_blank">
        <strong><action
            android:id="@+id/action_fragment_to_second_graph"
            app:destination="@id/second_graph" /></strong>
    </fragment>

    ...
</navigation>
<!-- included_graph.xml -->
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    <strong>android:id="@+id/second_graph"</strong>
    app:startDestination="@id/includedStart">

    <fragment
        android:id="@+id/includedStart"
        android:name="com.example.myapplication.IncludedStart"
        android:label="fragment_included_start"
        tools:layout="@layout/fragment_included_start" />
</navigation>

مصادر إضافية

لمزيد من المعلومات عن التنقّل، يمكنك الرجوع إلى المراجع الإضافية التالية.

الدروس التطبيقية حول الترميز

الفيديوهات