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 для кожного екрану. Весь життєвий цикл керується через 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 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.

Обговорити проект

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