Компонент Navigation использует граф навигации для управления навигацией в приложении. Граф навигации – это структура данных, которая содержит все пункты назначения в приложении и связи между ними.
Типы целевых страниц
Существует три основных типа пунктов назначения: размещенные, диалоговые и действия. В таблице ниже описаны эти три типа целевых страниц и их назначение.
Тип |
Описание |
Примеры использования |
|---|---|---|
Размещенные |
Заполняет весь хост навигации. То есть размер размещенного пункта назначения совпадает с размером хоста навигации, а предыдущие пункты назначения не видны. |
Главный экран и экран с подробной информацией. |
Диалоговое окно |
Показывает компоненты интерфейса оверлея. Этот интерфейс не привязан к местоположению или размеру хоста навигации. Предыдущие пункты назначения видны под пунктом назначения. |
Оповещения, выбор, формы. |
Действия |
Представляет уникальные экраны или функции в приложении. |
Служит точкой выхода из графа навигации, которая запускает новое действие Android, управляемое отдельно от компонента Navigation. В современной разработке для Android приложение состоит из одного действия. Поэтому целевые местоположения действий лучше всего использовать при взаимодействии со сторонними действиями или в рамках процесса переноса. |
В этом документе приведены примеры размещенных целевых страниц, которые являются наиболее распространенными и основными. Информацию о других целевых страницах можно найти в следующих руководствах:
Компоненты Framework
Хотя во всех случаях применяется один и тот же общий рабочий процесс, то, как именно вы создаете хост навигации и граф, зависит от используемой вами платформы пользовательского интерфейса.
- Compose. Используйте composable-функцию
NavHost. Добавьте в негоNavGraphс помощью Kotlin DSL. График можно создать двумя способами:- В составе NavHost. Граф навигации создается непосредственно при добавлении
NavHost. - Программно. Используйте метод
NavController.createGraph(), чтобы создатьNavGraphи передать его непосредственно вNavHost.
- В составе NavHost. Граф навигации создается непосредственно при добавлении
- Фрагменты. При использовании фрагментов с фреймворком Views UI используйте
NavHostFragmentв качестве хоста. Граф навигации можно создать несколькими способами:- Программно. Используйте Kotlin DSL, чтобы создать
NavGraphи применить его непосредственно кNavHostFragment.- Функция
createGraph(), используемая с Kotlin DSL, одинакова и для фрагментов, и для Compose.
- Функция
- XML. Напишите хост навигации и граф непосредственно в XML.
- Редактор Android Studio. Используйте редактор графического интерфейса пользователя в Android Studio, чтобы создать и настроить граф в виде XML-файла ресурсов.
- Программно. Используйте Kotlin DSL, чтобы создать
Написать
В Compose используйте сериализуемый объект или класс, чтобы определить маршрут. Маршрут описывает, как добраться до пункта назначения, и содержит всю информацию, необходимую для пункта назначения.
Используйте аннотацию @Serializable, чтобы автоматически создавать необходимые методы сериализации и десериализации для типов маршрутов. Эта аннотация предоставляется плагином Kotlin Serialization. Следуйте этим инструкциям, чтобы добавить плагин.
Определив маршруты, используйте composable-функцию NavHost, чтобы создать граф навигации. Пример:
@Serializable
object Profile
@Serializable
object FriendsList
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Profile) {
composable<Profile> { ProfileScreen( /* ... */ ) }
composable<FriendsList> { FriendsListScreen( /* ... */ ) }
// Add more destinations similarly.
}
- Каждый из двух маршрутов,
ProfileиFriendsList, представлен сериализуемым объектом. - Вызов composable-функции
NavHostпередаетNavControllerи маршрут для начального пункта назначения. - Лямбда-выражение, переданное в
NavHost, в конечном итоге вызываетNavController.createGraph()и возвращаетNavGraph. - Каждый маршрут передается в качестве аргумента типа в
NavGraphBuilder.composable<T>(), который добавляет пункт назначения в результирующийNavGraph. - Лямбда-функция, переданная в
composable, – это то, чтоNavHostпоказывает для этого пункта назначения.
Как работает лямбда-функция
Чтобы лучше понять лямбда-выражение, создающее NavGraph, представьте, что для построения того же графа, что и в предыдущем фрагменте, вы можете создать NavGraph отдельно с помощью NavController.createGraph() и передать его непосредственно в NavHost:
val navGraph by remember(navController) {
navController.createGraph(startDestination = Profile)) {
composable<Profile> { ProfileScreen( /* ... */ ) }
composable<FriendsList> { FriendsListScreen( /* ... */ ) }
}
}
NavHost(navController, navGraph)
Передача аргументов
Если вам нужно передать данные в пункт назначения, определите маршрут с помощью класса, у которого есть параметры. Например, маршрут Profile – это класс данных с параметром name.
@Serializable
data class Profile(val name: String)
Всякий раз, когда вам нужно передать аргументы в этот пункт назначения, вы создаете экземпляр класса маршрута, передавая аргументы конструктору класса.
Для необязательных аргументов создайте поля, допускающие значение NULL, со значением по умолчанию.
@Serializable
data class Profile(val nickname: String? = null)
Получение экземпляра маршрута
Экземпляр маршрута можно получить с помощью NavBackStackEntry.toRoute() или SavedStateHandle.toRoute(). При создании целевой страницы с помощью composable() параметр NavBackStackEntry доступен.
@Serializable
data class Profile(val name: String)
val navController = rememberNavController()
NavHost(navController = navController, startDestination = Profile(name="John Smith")) {
composable<Profile> { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(name = profile.name) }
}
Обратите внимание на следующее:
- Маршрут
Profileуказывает начальный пункт назначения в графе навигации, а"John Smith"– аргумент дляname. - Целевая страница – это блок
composable<Profile>{}. - Функция
ProfileScreenпринимает значениеprofile.nameдля собственного аргументаname. - Таким образом, значение
"John Smith"передается вProfileScreen.
Минимальный пример
Ниже приведен полный пример совместного использования NavController и NavHost.
@Serializable
data class Profile(val name: String)
@Serializable
object FriendsList
// Define the ProfileScreen composable.
@Composable
fun ProfileScreen(
profile: Profile
onNavigateToFriendsList: () -> Unit,
) {
Text("Profile for ${profile.name}")
Button(onClick = { onNavigateToFriendsList() }) {
Text("Go to Friends List")
}
}
// Define the FriendsListScreen composable.
@Composable
fun FriendsListScreen(onNavigateToProfile: () -> Unit) {
Text("Friends List")
Button(onClick = { onNavigateToProfile() }) {
Text("Go to Profile")
}
}
// Define the MyApp composable, including the `NavController` and `NavHost`.
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(navController, startDestination = Profile(name = "John Smith")) {
composable<Profile> { backStackEntry ->
val profile: Profile = backStackEntry.toRoute()
ProfileScreen(
profile = profile,
onNavigateToFriendsList = {
navController.navigate(route = FriendsList)
}
)
}
composable<FriendsList> {
FriendsListScreen(
onNavigateToProfile = {
navController.navigate(
route = Profile(name = "Aisha Devi")
)
}
)
}
}
}
Как показано во фрагменте, вместо передачи NavController в composable-функции, передайте событие в NavHost. То есть у composable-функций должен быть параметр типа () -> Unit, для которого NavHost передает лямбда-выражение, вызывающее NavController.navigate().
Фрагменты
Как описано в предыдущих разделах, при использовании фрагментов у вас есть возможность создать граф навигации программно с помощью Kotlin DSL, XML или редактора Android Studio.
Ниже подробно описаны эти подходы.
Программно
Kotlin DSL предоставляет программный способ создания графа навигации с фрагментами. Во многих отношениях это более аккуратный и современный способ, чем использование XML-файла ресурсов.
Рассмотрим следующий пример, в котором реализован граф навигации с двумя экранами.
Сначала создайте объект NavHostFragment, который не должен содержать элемент app:navGraph:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
Затем передайте id объекта NavHostFragment в NavController.findNavController. Это связывает NavController с NavHostFragment.
Затем вызов NavController.createGraph() связывает граф с NavController и, следовательно, с NavHostFragment:
@Serializable
data class Profile(val name: String)
@Serializable
object FriendsList
// Retrieve the NavController.
val navController = findNavController(R.id.nav_host_fragment)
// Add the graph to the NavController with `createGraph()`.
navController.graph = navController.createGraph(
startDestination = Profile(name = "John Smith")
) {
// Associate each destination with one of the route constants.
fragment<ProfileFragment, Profile> {
label = "Profile"
}
fragment<FriendsListFragment, FriendsList>() {
label = "Friends List"
}
// Add other fragment destinations similarly.
}
Использование DSL таким образом очень похоже на рабочий процесс, описанный в предыдущем разделе Compose. Например, и там, и здесь функция NavController.createGraph() генерирует NavGraph. Аналогично, в то время как NavGraphBuilder.composable() добавляет в граф составные пункты назначения, NavGraphBuilder.fragment() добавляет пункт назначения фрагмента.
Подробнее о том, как использовать Kotlin DSL, рассказывается в статье Как создать граф с помощью NavGraphBuilder DSL.
XML
Вы можете написать XML-код самостоятельно. Приведенный ниже пример аналогичен примеру с двумя экранами из предыдущего раздела.
Сначала создайте NavHostFragment. Это хост навигации, который содержит фактический граф навигации.
Минимальная реализация NavHostFragment:
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_graph" />
</FrameLayout>
Объект NavHostFragment содержит атрибут app:navGraph. Используйте этот атрибут, чтобы подключить граф навигации к хосту навигации. Ниже приведен пример реализации графа.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/nav_graph"
app:startDestination="@id/profile">
<fragment
android:id="@+id/profile"
android:name="com.example.ProfileFragment"
android:label="Profile">
<!-- Action to navigate from Profile to Friends List. -->
<action
android:id="@+id/action_profile_to_friendslist"
app:destination="@id/friendslist" />
</fragment>
<fragment
android:id="@+id/friendslist"
android:name="com.example.FriendsListFragment"
android:label="Friends List" />
<!-- Add other fragment destinations similarly. -->
</navigation>
Действия позволяют определить связи между разными целевыми сервисами. В этом примере фрагмент profile содержит действие, которое перенаправляет на friendslist. Подробнее о том, как использовать действия и фрагменты навигации…
Редактор
Управлять графом навигации приложения можно с помощью редактора навигации в Android Studio. По сути, это графический интерфейс пользователя, который можно использовать для создания и редактирования XML-файла NavigationFragment, как описано в предыдущем разделе.
Подробнее о редакторе навигации…
Вложенные графики
Вы также можете использовать вложенные графы. Это предполагает использование графа в качестве пункта назначения навигации. Подробнее о вложенных графах…
Дополнительные материалы
Дополнительную информацию о навигации можно найти в следующих руководствах:
- Обзор. Ознакомьтесь с общими сведениями о компоненте Navigation.
- Целевые страницы с действиями. Примеры реализации целевых страниц, на которых пользователь может выполнить определенные действия.
- Пункты назначения диалоговых окон. Примеры создания пунктов назначения, которые перенаправляют пользователя в диалоговое окно.
- Как проложить маршрут до пункта назначения. Подробное руководство по навигации от одного пункта назначения до другого.
- Вложенные графы. Подробное руководство по вложению одного графа навигации в другой.