Вложенные графики,Вложенные графики

Потоки входа, мастера и другие подпотоки в вашем приложении обычно лучше всего представлять в виде вложенных графов навигации . Благодаря такому вложению автономных потоков навигации основной поток пользовательского интерфейса вашего приложения становится проще для понимания и управления.

Кроме того, вложенные графики можно использовать повторно. Они также обеспечивают определенный уровень инкапсуляции — пункты назначения за пределами вложенного графа не имеют прямого доступа ни к одному из пунктов назначения внутри вложенного графа. Вместо этого им следует navigate() к самому вложенному графу, где внутренняя логика может измениться, не затрагивая остальную часть графа.

Пример

Граф навигации верхнего уровня вашего приложения должен начинаться с начального пункта назначения, который пользователь видит при запуске приложения, и должен включать пункты назначения, которые он видит при перемещении по вашему приложению.

Рисунок 1. Граф навигации верхнего уровня.

Используя в качестве примера граф навигации верхнего уровня на рисунке 1, предположим, что вы хотите, чтобы пользователь видел экраны title_screen и регистрации только при первом запуске приложения. После этого информация о пользователе сохраняется, и при последующих запусках приложения вы должны перенести ее прямо на экран матча .

Рекомендуется установить экран матча в качестве начальной точки навигационного графа верхнего уровня и переместить экраны заголовка и регистрации во вложенный график, как показано на рисунке 1:

Рисунок 2. Граф навигации верхнего уровня теперь содержит вложенный график.

Когда откроется экран матча, проверьте, есть ли зарегистрированный пользователь. Если пользователь не зарегистрирован, перейдите к экрану регистрации.

Дополнительные сведения о сценариях условной навигации см. в разделе Условная навигация .

Сочинить

Чтобы создать вложенный граф навигации с помощью Compose, используйте функцию NavGraphBuilder.navigation() . Вы используете navigation() так же, как NavGraphBuilder.composable() и NavGraphBuilder.dialog() при добавлении пунктов назначения на график.

Основное отличие состоит в том, что navigation создает вложенный график, а не новый пункт назначения. Затем вы вызываете composable() и dialog() в лямбда-выражении 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. Щелкните вложенный график. На панели «Атрибуты» отображаются следующие атрибуты:

    • Введите , который содержит «Вложенный график».
    • ID , который содержит назначенный системой идентификатор вложенного графа. Этот идентификатор используется для ссылки на вложенный график из вашего кода.
  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. В своем коде передайте идентификатор ресурса действия, соединяющего корневой граф с вложенным графом:

Котлин

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

Ява

Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
  1. Вернувшись на вкладку «Дизайн» , вернитесь к корневому графу, нажав «Корень» .

Ссылка на другие навигационные графики с включением

Другой способ модульной структуры вашего графа — включить один граф в другой с помощью элемента <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>

Дополнительные ресурсы

Чтобы узнать больше о навигации, обратитесь к следующим дополнительным ресурсам.

Образцы

Кодлабы

Видео