نمودارهای تو در تو

جریان‌های ورود به سیستم، ویزاردها یا سایر جریان‌های فرعی درون برنامه شما معمولاً به بهترین شکل به صورت نمودارهای ناوبری تو در تو نمایش داده می‌شوند. با تو در تو کردن جریان‌های فرعی مستقل به این روش، جریان اصلی رابط کاربری برنامه شما راحت‌تر قابل درک و مدیریت است.

علاوه بر این، گراف‌های تودرتو قابل استفاده مجدد هستند. آن‌ها همچنین سطحی از کپسوله‌سازی را فراهم می‌کنند - مقصدهای خارج از گراف تودرتو به هیچ یک از مقصدهای درون گراف تودرتو دسترسی مستقیم ندارند. در عوض، آن‌ها باید navigate() ، جایی که منطق داخلی می‌تواند بدون تأثیر بر بقیه گراف تغییر کند.

مثال

نمودار ناوبری سطح بالای برنامه شما باید با مقصد اولیه‌ای که کاربر هنگام اجرای برنامه می‌بیند شروع شود و شامل مقاصدی باشد که هنگام حرکت در برنامه شما می‌بیند.

شکل ۱. یک نمودار ناوبری سطح بالا.

با استفاده از نمودار ناوبری سطح بالا از شکل ۱ به عنوان مثال، فرض کنید می‌خواهید کاربر را ملزم کنید که فقط هنگام اولین اجرای برنامه، صفحات title_screen و register را ببیند. پس از آن، اطلاعات کاربر ذخیره می‌شود و در اجراهای بعدی برنامه، باید او را مستقیماً به صفحه تطبیق ببرید.

به عنوان بهترین روش، صفحه تطبیق را به عنوان مقصد شروع نمودار ناوبری سطح بالا تنظیم کنید و صفحات عنوان و ثبت را به یک نمودار تو در تو منتقل کنید، همانطور که در شکل 1 نشان داده شده است:

شکل ۲. گراف ناوبری سطح بالا اکنون شامل یک گراف تو در تو است.

وقتی صفحه تطبیق ظاهر شد، بررسی کنید که آیا کاربر ثبت‌نام‌شده‌ای وجود دارد یا خیر. اگر کاربر ثبت‌نام نکرده است، او را به صفحه ثبت‌نام هدایت کنید.

برای اطلاعات بیشتر در مورد سناریوهای ناوبری مشروط، به ناوبری مشروط مراجعه کنید.

نوشتن

برای ایجاد یک گراف ناوبری تو در تو با استفاده از Compose، از تابع NavGraphBuilder.navigation() استفاده کنید. هنگام افزودن مقصد به یک گراف، navigation() درست مانند NavGraphBuilder.composable() و NavGraphBuilder.dialog() استفاده می‌کنید.

تفاوت اصلی این است که navigation به جای یک مقصد جدید، یک گراف تودرتو ایجاد می‌کند. سپس می‌توانید composable() و dialog() را درون لامبدا navigation() فراخوانی کنید تا مقاصد را به گراف تودرتو اضافه کنید.

در نظر بگیرید که چگونه قطعه کد زیر، گراف شکل ۲ را با استفاده از 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، می‌توانید از ویرایشگر ناوبری (Navigation Editor) برای ایجاد نمودار تو در تو استفاده کنید. برای انجام این کار، مراحل زیر را دنبال کنید:

  1. در ویرایشگر ناوبری، کلید Shift را فشار داده و نگه دارید و روی مقاصدی که می‌خواهید در نمودار تو در تو قرار دهید کلیک کنید.
  2. برای باز کردن منوی زمینه، کلیک راست کنید و گزینه Move to Nested Graph > New Graph را انتخاب کنید. مقصدها در یک گراف تو در تو محصور شده‌اند. شکل 2 یک گراف تو در تو را در ویرایشگر ناوبری نشان می‌دهد:

    شکل ۲. گراف تو در تو در ویرایشگر ناوبری
  3. روی نمودار تو در تو کلیک کنید. ویژگی‌های زیر در پنل ویژگی‌ها ظاهر می‌شوند:

    • نوع ، که شامل "نمودار تو در تو" است
    • ID ، که شامل یک شناسه اختصاص داده شده توسط سیستم برای گراف تو در تو است. این شناسه برای ارجاع به گراف تو در تو از کد شما استفاده می‌شود.
  4. برای نمایش مقاصد نمودار تو در تو، روی آن دوبار کلیک کنید.

  5. برای نمایش XML روی تب Text کلیک کنید. یک گراف ناوبری تو در تو به گراف اضافه شده است. این گراف ناوبری عناصر navigation مخصوص به خود را به همراه شناسه (ID) مخصوص به خود و یک ویژگی 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. در کد خود، شناسه منبع اکشنی را که گراف ریشه را به گراف تو در تو متصل می‌کند، ارسال کنید:

کاتلین

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

جاوا

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. به برگه Design برگردید، با کلیک روی Root به نمودار ریشه برگردید.

با 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">

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

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