NavHost — что это, построение графа и маршруты в Jetpack Compose

Автор: IT Sectr Опубликовано: 2026-06-30 Время чтения: 7 мин

NavHost — это composable-контейнер, который служит точкой входа для графа навигации в Jetpack Compose. Он связывает NavController с набором маршрутов и рендерит текущий экран в зависимости от состояния back stack. По данным Android Developers (2025), NavHost является обязательным компонентом для любого Compose-приложения с навигацией. Внутри NavHost регистрируются composable-маршруты с опциональными аргументами, deep links и анимацией. Каждый маршрут — это обычная composable-функция, которая получает NavBackStackEntry с данными перехода. NavHost автоматически обрабатывает back press, сохранение состояния и восстановление при реконфигурации.

Главное

  • NavHost — composable-контейнер, связывающий NavController с графом маршрутов и рендерящий текущий экран
  • composable() — функция регистрации маршрута с route, аргументами, deep links и анимацией переходов
  • startDestination — начальный маршрут, открываемый при создании NavHost
  • Аргументы задаются через navArgument с NavType для типизированной передачи данных между экранами
  • Анимация настраивается глобально или индивидуально через enterTransition, exitTransition параметры

Что такое NavHost в Jetpack Compose?

NavHost — это composable-функция, предоставляющая контейнер для отображения текущего экрана навигации. NavHost принимает NavController, startDestination и граф маршрутов, построенный через Kotlin DSL. При изменении текущего маршрута NavHost переключает отображаемый composable с заданной анимацией.

NavHost работает как переключатель экранов: он отслеживает текущий NavBackStackEntry из NavController и рендерит соответствующий composable-блок. Каждый экран — это независимая composable-функция, которая получает NavBackStackEntry с аргументами маршрута. Все экраны существуют в едином дереве композиции, но NavHost показывает только один за раз, скрывая остальные через анимацию.

В отличие от FragmentManager, NavHost не создаёт Fragment для каждого экрана. Весь lifecycle управляется через CompositionLifecycle — у composable-функций нет onStart/onResume, поэтому для side-эффектов используются LaunchedEffect и DisposableEffect. NavHost автоматически подписывается на NavController и перекомпоновывает UI при изменении маршрута.

По данным Google, NavHost является stable API с версии Navigation 2.4.0. Начиная с 2.8.0, NavHost поддерживает Type-Safe Navigation через Kotlin Serialization, что заменяет строковые route на data-классы. NavHost также поддерживает вложенные графы, что позволяет организовать навигацию по модулям.

NavHost создаётся с двумя обязательными параметрами: navController (экземпляр NavHostController) и startDestination (строка маршрута первого экрана). Третий параметр — builder-блок, в котором регистрируются все маршруты через composable(), navigation() и dialog().

kotlin
@Composable
fun AppNavHost(navController: NavHostController) {
    NavHost(
        navController = navController,
        startDestination = "home"
    ) {
        composable("home") { HomeScreen(navController) }
        composable("settings") { SettingsScreen(navController) }
    }
}

startDestination — это маршрут, который открывается при первом запуске NavHost. Если back stack пуст, NavHost автоматически добавляет startDestination в стек. При реконфигурации (поворот экрана) NavHost восстанавливает последний маршрут из savedState, а не startDestination.

Для BottomNavigation startDestination — это один из маршрутов нижней панели. Остальные маршруты панели добавляются как отдельные composable-записи. NavHost должен быть размещён внутри Scaffold.content — там, где отображается основной контент приложения. NavHost занимает всю доступную высоту за вычетом TopAppBar и BottomNavigation.

Регистрация маршрутов через composable

Функция composable(route, arguments, deepLinks, enterTransition, exitTransition, content) регистрирует маршрут в графе NavHost. Параметр route — это строка, описывающая путь с опциональными плейсхолдерами вида {paramName}. Плейсхолдер заменяется на конкретное значение при навигации.

Content-блок composable получает NavBackStackEntry, из которого извлекаются аргументы. Composable-функция экрана рендерится только когда текущий маршрут NavController совпадает с route. При несовпадении composable удаляется из композиции, но его состояние может быть сохранено через rememberSaveable или ViewModel с SavedStateHandle.

kotlin
composable(
    route = "article/{articleId}",
    arguments = listOf(navArgument("articleId") {
        type = NavType.IntType
        defaultValue = 0
    }),
    deepLinks = listOf(navDeepLink { uriPattern = "https://app.example/article/{articleId}" })
) { backStackEntry ->
    val articleId = backStackEntry.arguments?.getInt("articleId") ?: 0
    ArticleScreen(articleId = articleId)
}

Количество composable-записей внутри NavHost может быть любым — от пары до сотен. Для больших приложений маршруты разбиваются по модулям и подключаются через вложенные графы. Каждый composable может иметь собственные настройки анимации, deep links и аргументов.

Аргументы и типизированные параметры маршрутов

Аргументы маршрута определяются через параметр arguments: List<NamedNavArgument> в composable(). Каждый аргумент задаётся через navArgument(name) { type; defaultValue }. NavType определяет тип аргумента: StringType, IntType, LongType, FloatType, BoolType, ParcelableType и ReferenceType.

Параметр маршрутаПример routeNavType
Путь (path)"user/{id}"NavType.IntType
Запрос (query)"search?q={query}"NavType.StringType
Опциональный"details/{id}?tab={tab}"StringType + defaultValue=""
Parcelable"checkout/{order}"NavType.ParcelableType

Аргументы извлекаются из NavBackStackEntry через arguments?.getInt("id"). Для обязательных аргументов defaultValue может отсутствовать — NavType будет использовать null. Для опциональных аргументов defaultValue задаётся обязательным образом, иначе навигация выбросит исключение при отсутствии параметра.

С версии Navigation 2.8.0 рекомендуется Type-Safe Navigation: определите sealed class или data class для маршрутов с Kotlin Serialization. Вместо строкового route используйте composable<RouteType> { backStackEntry -> }. Это исключает опечатки в route и автоматически генерирует NavType для аргументов. Для миграции добавьте зависимость navigation-compose-typesafe и плагин Kotlin Serialization.

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

nested graphs — механизм группировки маршрутов внутри NavHost через функцию navigation(route, startDestination). Вложенный граф имеет собственный route-префикс и startDestination, а все его маршруты доступны через префикс. nested graphs используются для модульной архитектуры, где каждый feature-модуль регистрирует свой подграф.

Преимущества вложенных графов: изоляция маршрутов внутри модуля, единый back stack для группы экранов, возможность навигации по префиксу без раскрытия внутренней структуры. Например, граф "auth" содержит "auth/login" и "auth/register". Навигация возможна как по полному маршруту, так и по префиксу с редиректом на startDestination.

kotlin
NavHost(navController = navController, startDestination = "main") {
    composable("main") { MainScreen(navController) }
    navigation(
        route = "auth",
        startDestination = "auth/login"
    ) {
        composable("auth/login") { LoginScreen(navController) }
        composable("auth/register") { RegisterScreen(navController) }
    }
}

nested graphs поддерживают передачу аргументов на уровне графа: параметры, объявленные в route графа, передаются во все внутренние маршруты. Для очистки вложенного графа используйте popBackStack(route) — удалит все внутренние записи. Вложенные графы не ограничены по глубине, но рекомендуется не более 3 уровней для читаемости.

Анимация и кастомизация переходов

NavHost поддерживает анимацию переходов между composable-маршрутами через параметры enterTransition, exitTransition, popEnterTransition и popExitTransition. Анимации задаются один раз для NavHost и применяются ко всем маршрутам, либо индивидуально для каждого composable. По умолчанию анимация отключена.

Типовая конфигурация: enterTransition = slideInHorizontally(initialOffsetX = { it }) — экран заезжает справа; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — экран уезжает влево. Для pop-анимации направления зеркальны: экран заезжает слева и уезжает вправо. Для BottomNavigation используется fadeIn/fadeOut без слайда.

kotlin
NavHost(
    navController = navController,
    startDestination = "home",
    enterTransition = { slideInHorizontally(initialOffsetX = { it }) + fadeIn() },
    exitTransition = { slideOutHorizontally(targetOffsetX = { -it }) + fadeOut() },
    popEnterTransition = { slideInHorizontally(initialOffsetX = { -it }) + fadeIn() },
    popExitTransition = { slideOutHorizontally(targetOffsetX = { it }) + fadeOut() }
) { /* composable routes */ }

Кастомные анимации создаются через Compose Animation API: AnimatedContentTransitionScope предоставляет доступ к размерам контейнера, прогрессу анимации и direction. Для shared element transition (один элемент плавно переходит на другой экран) требуется библиотека Accompanist Navigation Animation или кастомная реализация через sharedElement Modifier. По данным Android Developers (2025), slide-анимация по умолчанию (enter справа, exit влево) используется в 80% Android-приложений с навигацией.

Часто задаваемые вопросы

Можно ли использовать несколько NavHost в одном Activity?

Технически да, но не рекомендуется. Каждый NavHost создаёт независимый back stack, что нарушает единую навигацию. Исключение — раздельные области, например, NavHost для основного контента и NavHost для BottomSheet с собственной навигацией.

Чем отличается NavHost от Scaffold в Compose?

NavHost — контейнер навигации, переключающий экраны. Scaffold — макет всей страницы (TopAppBar, BottomNavigation, FloatingActionButton). Обычно NavHost размещается внутри Scaffold.content. Scaffold не управляет навигацией, а только предоставляет слоты для UI-компонентов.

Как передать ViewModel между экранами через NavHost?

ViewModel создаётся в рамках NavBackStackEntry через viewModel(). Для шаринга ViewModel между экранами используйте parentNavController: shared ViewModel привяжите к родительскому entry. Альтернатива — DI (Hilt/Koin) с scope на NavGraph.

Почему NavHost пересоздаёт composable при каждом переходе?

Это нормальное поведение — NavHost удаляет composable из композиции при уходе с маршрута. Для сохранения состояния используйте rememberSaveable для UI-состояния и ViewModel с SavedStateHandle для бизнес-логики.

Как добавить обработку 404 (неизвестный маршрут) в NavHost?

Добавьте последний маршрут composable("404") и навигацию на него при неизвестном deep link. В NavHost нет catch-all маршрута — проверяйте маршрут в intent-обработчике Deep Link перед navigate(). Если route не найден — navigate на 404.

Итоги

  • NavHost — composable-контейнер Navigation Compose, связывающий NavController с графом маршрутов и рендерящий текущий экран
  • composable() регистрирует маршрут с route, аргументами (NavType), deep links и анимацией
  • startDestination — начальный маршрут, открываемый при первом запуске NavHost
  • Аргументы передаются через плейсхолдеры {param} с NavType для типизации и defaultValue для опциональных параметров
  • Вложенные графы через navigation() позволяют группировать маршруты по модулям с изолированным back stack
  • Анимация переходов настраивается через enterTransition/exitTransition с использованием Compose Animation API
  • NavHost автоматически обрабатывает back press, сохранение состояния и deep links без дополнительного кода

Мы разработаем мобильное приложение под ключ

IT Sectr создаёт приложения для iOS и Android для стартапов и бизнеса с 2017 года. Мы проконсультируем вас и предложим наилучшее решение.

Обсудить проект

Читайте также