Создайте свой навигационный график, Создайте свой навигационный график

Компонент «Навигация» использует граф навигации для управления навигацией вашего приложения. Граф навигации — это структура данных, которая содержит все пункты назначения в вашем приложении и связи между ними.

Типы пунктов назначения

Существует три основных типа мест назначения: размещенное, диалоговое и действие. В следующей таблице описаны эти три типа назначения и их назначение.

Тип

Описание

Варианты использования

Хостинг

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

Главный и подробный экраны.

Диалог

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

Оповещения, выборки, формы.

Активность

Представляет уникальные экраны или функции приложения.

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

В современной разработке Android приложение состоит из одного действия. Поэтому места назначения действий лучше всего использовать при взаимодействии с действиями третьих лиц или в рамках процесса миграции .

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

Рамки

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

  • Составление: используйте составной элемент NavHost . Добавьте к нему NavGraph с помощью Kotlin DSL . Создать график можно двумя способами:
    • Как часть NavHost: создайте граф навигации непосредственно в рамках добавления NavHost .
    • Программно: используйте метод NavController.createGraph() , чтобы создать NavGraph и передать его напрямую в NavHost .
  • Фрагменты. При использовании фрагментов с платформой пользовательского интерфейса представлений используйте NavHostFragment в качестве узла. Существует несколько способов создания навигационного графа:
    • Программно: используйте Kotlin DSL для создания NavGraph и непосредственного применения его к NavHostFragment .
      • Функция createGraph() , используемая с Kotlin DSL как для фрагментов, так и для Compose, одинакова.
    • XML: напишите свой навигационный хост и график непосредственно в XML.
    • Редактор Android Studio: используйте редактор графического интерфейса в Android Studio, чтобы создать и настроить график в виде файла ресурсов XML.

Сочинить

В Compose используйте сериализуемый объект или класс для определения маршрута . Маршрут описывает, как добраться до пункта назначения, и содержит всю информацию, необходимую для пункта назначения. После того, как вы определили свои маршруты, используйте компонуемый 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.
}
  1. Сериализуемый объект представляет каждый из двух маршрутов: Profile и FriendsList .
  2. Вызов компонуемого NavHost передает NavController и маршрут для начального пункта назначения.
  3. Лямбда, передаваемая в NavHost в конечном итоге вызывает NavController.createGraph() и возвращает NavGraph .
  4. Каждый маршрут предоставляется в качестве аргумента типа функции NavGraphBuilder.composable<T>() которая добавляет пункт назначения к результирующему NavGraph .
  5. Лямбда, передаваемая в 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 вашим компонуемым объектам необходимо предоставить событие NavHost . То есть ваши составные элементы должны иметь параметр типа () -> 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 , как показано в предыдущем разделе.

Дополнительную информацию см. в разделе Редактор навигации .

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

Вы также можете использовать вложенные графики. Это предполагает использование графика в качестве пункта назначения навигации. Дополнительные сведения см. в разделе Вложенные графики .

Дальнейшее чтение

Дополнительные сведения об основных концепциях навигации см. в следующих руководствах:

  • Обзор : обязательно прочтите общий обзор компонента навигации.
  • Направления действий : примеры реализации мест назначения, которые перенаправляют пользователя к действиям.
  • Пункты назначения диалога : примеры создания пунктов назначения, которые перенаправляют пользователя в диалог.
  • Навигация к пункту назначения : подробное руководство, описывающее, как перемещаться от одного пункта назначения к другому.
  • Вложенные графики : подробное руководство о том, как вложить один навигационный график в другой.