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

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

Когда откроется экран матча, проверьте, есть ли зарегистрированный пользователь. Если пользователь не зарегистрирован, переведите его на экран регистрации.
Дополнительную информацию о сценариях условной навигации см. в разделе Условная навигация .
Сочинять
Чтобы создать вложенный навигационный граф с помощью 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 вы можете создать вложенный график с помощью редактора навигации. Для этого выполните следующие действия:
- В редакторе навигации нажмите и удерживайте клавишу Shift и щелкните пункты назначения, которые вы хотите включить во вложенный график.
Щелкните правой кнопкой мыши, чтобы открыть контекстное меню, и выберите «Переместить во вложенный график» > «Новый график» . Целевые объекты заключены во вложенный график. На рисунке 2 показан вложенный график в редакторе навигации :
Рисунок 2. Вложенный график в редакторе навигации Щелкните вложенный график. На панели «Атрибуты» появятся следующие атрибуты:
- Тип , содержащий «Вложенный граф»
- ID , содержащий системный идентификатор вложенного графа. Этот идентификатор используется для ссылки на вложенный граф из вашего кода.
Дважды щелкните по вложенному графику, чтобы отобразить его пункты назначения.
Перейдите на вкладку «Текст» , чтобы переключиться в режим просмотра 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>
В вашем коде передайте идентификатор ресурса действия, соединяющего корневой граф с вложенным графом:
Котлин
view.findNavController().navigate(R.id.action_mainFragment_to_sendMoneyGraph)
Ява
Navigation.findNavController(view).navigate(R.id.action_mainFragment_to_sendMoneyGraph);
- Вернитесь на вкладку «Конструктор» , вернитесь к корневому графику, нажав кнопку «Корень» .
Ссылайтесь на другие навигационные графики с помощью 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>