Компонент «Навигация» обеспечивает поддержку приложений Jetpack Compose. Вы можете перемещаться между компонуемыми объектами, используя инфраструктуру и функции компонента «Навигация».
Для получения информации о последней альфа-версии библиотеки навигации, созданной специально для Compose, см. документацию Navigation 3 .
Настраивать
 Для поддержки Compose используйте следующую зависимость в файле build.gradle вашего модуля приложения: 
классный
dependencies { def nav_version = "2.9.5" implementation "androidx.navigation:navigation-compose:$nav_version" }
Котлин
dependencies { val nav_version = "2.9.5" implementation("androidx.navigation:navigation-compose:$nav_version") }
Начать
При реализации навигации в приложении реализуйте хост, граф и контроллер навигации. Подробнее см. в разделе «Обзор навигации ».
Создать NavController
 Информацию о создании NavController в Compose см. в разделе Compose статьи Создание навигационного контроллера .
Создать NavHost
 Информацию о создании NavHost в Compose см. в разделе «Compose» статьи «Разработка навигационного графика» .
Перейдите к компонуемому
Информацию о переходе к Composable см. в разделе Переход к месту назначения в документации по архитектуре.
Навигация с помощью аргументов
Информацию о передаче аргументов между составными пунктами назначения см. в разделе Составление статьи Разработка навигационного графика .
Извлекайте сложные данные при навигации
Настоятельно рекомендуется не передавать сложные объекты данных при навигации, а вместо этого передавать минимум необходимой информации, такой как уникальный идентификатор или другую форму идентификатора, в качестве аргументов при выполнении навигационных действий:
// Pass only the user ID when navigating to a new destination as argument
navController.navigate(Profile(id = "user1234"))
 Сложные объекты должны храниться в виде данных в едином источнике данных, например, в слое данных. Добравшись до пункта назначения после навигации, вы можете загрузить необходимую информацию из единого источника данных, используя переданный идентификатор. Чтобы получить аргументы в ViewModel , отвечающие за доступ к слою данных, используйте SavedStateHandle ViewModel :
class UserViewModel(
    savedStateHandle: SavedStateHandle,
    private val userInfoRepository: UserInfoRepository
) : ViewModel() {
    private val profile = savedStateHandle.toRoute<Profile>()
    // Fetch the relevant user information from the data layer,
    // ie. userInfoRepository, based on the passed userId argument
    private val userInfo: Flow<UserInfo> = userInfoRepository.getUserInfo(profile.id)
// …
}
Такой подход помогает предотвратить потерю данных при изменении конфигурации и любые несоответствия при обновлении или мутации рассматриваемого объекта.
Более подробное объяснение того, почему следует избегать передачи сложных данных в качестве аргументов, а также список поддерживаемых типов аргументов см. в разделе Передача данных между пунктами назначения .
Глубокие ссылки
 Navigation Compose поддерживает глубокие ссылки, которые также можно определить как часть функции composable() . Его параметр deepLinks принимает список объектов NavDeepLink , которые можно быстро создать с помощью метода navDeepLink() :
@Serializable data class Profile(val id: String)
val uri = "https://www.example.com"
composable<Profile>(
  deepLinks = listOf(
    navDeepLink<Profile>(basePath = "$uri/profile")
  )
) { backStackEntry ->
  ProfileScreen(id = backStackEntry.toRoute<Profile>().id)
}
 Эти глубокие ссылки позволяют связать определённый URL, действие или MIME-тип с компонуемым объектом. По умолчанию эти глубокие ссылки не доступны внешним приложениям. Чтобы сделать эти глубокие ссылки доступными извне, необходимо добавить соответствующие элементы <intent-filter> в файл manifest.xml вашего приложения. Чтобы включить глубокую ссылку в предыдущем примере, необходимо добавить следующее в элемент <activity> манифеста:
<activity …>
  <intent-filter>
    ...
    <data android:scheme="https" android:host="www.example.com" />
  </intent-filter>
</activity>
Навигация автоматически переходит по глубоким ссылкам в этот компонуемый элемент, когда глубокая ссылка активируется другим приложением.
 Эти же глубокие ссылки можно использовать для создания PendingIntent с соответствующей глубокой ссылкой из компонуемого объекта:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
    Intent.ACTION_VIEW,
    "https://www.example.com/profile/$id".toUri(),
    context,
    MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
    addNextIntentWithParentStack(deepLinkIntent)
    getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
 Затем вы можете использовать этот deepLinkPendingIntent , как и любой другой PendingIntent для открытия вашего приложения в месте назначения глубокой ссылки.
Вложенная навигация
Информацию о создании вложенных навигационных графиков см. в разделе Вложенные графики .
Создайте адаптивную нижнюю навигационную панель и навигационную направляющую
 NavigationSuiteScaffold отображает соответствующий навигационный интерфейс в зависимости от WindowSizeClass , в котором визуализируется ваше приложение. На компактных экранах NavigationSuiteScaffold отображает нижнюю панель навигации; на развернутом экране вместо неё отображается навигационная панель.
Дополнительную информацию см. в разделе Создание адаптивной навигации .
Взаимодействие
Если вы хотите использовать компонент навигации с Compose, у вас есть два варианта:
- Определите навигационный граф с компонентом «Навигация» для фрагментов.
-  Определите навигационный граф с NavHostв Compose, используя пункты назначения Compose. Это возможно только в том случае, если все экраны в навигационном графе являются компонуемыми.
Поэтому для приложений, сочетающих Compose и Views, рекомендуется использовать компонент навигации на основе фрагментов. Фрагменты будут содержать экраны на основе View, экраны Compose и экраны, использующие как View, так и Compose. После того, как содержимое каждого фрагмента будет добавлено в Compose, следующим шагом будет объединение всех этих экранов с помощью компонента Navigation Compose и удаление всех фрагментов.
Переход из Compose с навигацией для фрагментов
Чтобы изменить назначения внутри кода Compose, вы предоставляете события, которые могут быть переданы и вызваны любым компонуемым объектом в иерархии:
@Composable
fun MyScreen(onNavigate: (Int) -> Unit) {
    Button(onClick = { onNavigate(R.id.nav_profile) } { /* ... */ }
}
 В вашем фрагменте вы создаете мост между Compose и компонентом навигации на основе фрагмента, находя NavController и выполняя навигацию к месту назначения:
override fun onCreateView( /* ... */ ) {
    setContent {
        MyScreen(onNavigate = { dest -> findNavController().navigate(dest) })
    }
}
 В качестве альтернативы вы можете передать NavController вниз по иерархии Compose. Однако предоставление простых функций гораздо удобнее для повторного использования и тестирования.
Тестирование
 Отделите навигационный код от ваших компонуемых пунктов назначения, чтобы иметь возможность тестировать каждый компонуемый элемент изолированно, отдельно от компонуемого элемента NavHost .
 Это означает, что вам не следует передавать navController напрямую в любой компонуемый объект , а вместо этого передавать навигационные обратные вызовы в качестве параметров. Это позволяет тестировать все компонуемые объекты по отдельности, поскольку им не требуется экземпляр navController в тестах.
 Уровень косвенности, обеспечиваемый composable лямбда-функцией, позволяет отделить код навигации от самой компонуемой функции. Это работает в двух направлениях:
- Передавайте в компонуемый объект только проанализированные аргументы.
-  Передайте лямбда-выражения, которые должны запускаться составным элементом для навигации, а не самим NavController.
 Например, составной элемент ProfileScreen , который принимает в качестве входных данных идентификатор userId и позволяет пользователям переходить на страницу профиля друга, может иметь следующую сигнатуру:
@Composable
fun ProfileScreen(
    userId: String,
    navigateToFriendProfile: (friendUserId: String) -> Unit
) {
 …
}
 Таким образом, компонуемый элемент ProfileScreen работает независимо от Navigation, что позволяет тестировать его отдельно. Лямбда- composable будет инкапсулировать минимальную логику, необходимую для преодоления разрыва между API навигации и компонуемым элементом:
@Serializable data class Profile(id: String)
composable<Profile> { backStackEntry ->
    val profile = backStackEntry.toRoute<Profile>()
    ProfileScreen(userId = profile.id) { friendUserId ->
        navController.navigate(route = Profile(id = friendUserId))
    }
}
 Рекомендуется писать тесты, охватывающие требования к навигации вашего приложения, путем тестирования NavHost , действий навигации, передаваемых вашим компонуемым элементам, а также ваших отдельных компонуемых экранов.
 Тестирование NavHost
 Чтобы начать тестирование NavHost , добавьте следующую зависимость для тестирования навигации: 
dependencies {
// ...
  androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
  // ...
}
Оберните NavHost вашего приложения в составной объект, который принимает NavHostController в качестве параметра. 
@Composable
fun AppNavHost(navController: NavHostController){
  NavHost(navController = navController){ ... }
}
Теперь вы можете протестировать AppNavHost и всю навигационную логику, определённую внутри NavHost , передав экземпляр артефакта тестирования навигации TestNavHostController . Тест пользовательского интерфейса, проверяющий начальную точку назначения вашего приложения и NavHost , будет выглядеть следующим образом: 
class NavigationTest {
    @get:Rule
    val composeTestRule = createComposeRule()
    lateinit var navController: TestNavHostController
    @Before
    fun setupAppNavHost() {
        composeTestRule.setContent {
            navController = TestNavHostController(LocalContext.current)
            navController.navigatorProvider.addNavigator(ComposeNavigator())
            AppNavHost(navController = navController)
        }
    }
    // Unit test
    @Test
    fun appNavHost_verifyStartDestination() {
        composeTestRule
            .onNodeWithContentDescription("Start Screen")
            .assertIsDisplayed()
    }
}
Тестирование навигационных действий
Вы можете протестировать реализацию навигации несколькими способами: щелкнув мышью по элементам пользовательского интерфейса и затем либо проверив отображаемый пункт назначения, либо сравнив ожидаемый маршрут с текущим маршрутом.
Поскольку вы хотите протестировать реализацию конкретного приложения, клики по пользовательскому интерфейсу предпочтительнее. Чтобы узнать, как тестировать это вместе с отдельными компонуемыми функциями изолированно, ознакомьтесь с практической работой по тестированию в Jetpack Compose .
 Вы также можете использовать navController для проверки своих утверждений, сравнивая текущий маршрут с ожидаемым, используя currentBackStackEntry navController : 
@Test
fun appNavHost_clickAllProfiles_navigateToProfiles() {
    composeTestRule.onNodeWithContentDescription("All Profiles")
        .performScrollTo()
        .performClick()
    assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}
Дополнительные сведения об основах тестирования Compose см. в разделах «Тестирование макета Compose» и «Тестирование в Jetpack Compose» . Подробнее о расширенном тестировании кода навигации см. в руководстве «Тестирование навигации» .
Узнать больше
Чтобы узнать больше о Jetpack Navigation, ознакомьтесь со статьей Начало работы с компонентом Navigation или пройдите практическую работу по созданию кода Jetpack Compose Navigation .
Чтобы узнать, как разработать навигацию вашего приложения, чтобы она адаптировалась к разным размерам экрана, ориентациям и форм-факторам, ознакомьтесь со статьей Навигация для адаптивных пользовательских интерфейсов .
Чтобы узнать о более продвинутой реализации навигации Compose в модульном приложении, включая такие концепции, как вложенные графики и интеграция нижней панели навигации, взгляните на приложение Now in Android на GitHub.
Образцы
Рекомендовано для вас
- Примечание: текст ссылки отображается, когда JavaScript отключен.
- Material Design 2 в Compose
- Перенести навигацию Jetpack в навигацию Compose
- Где поднять состояние
