NavHost — це composable-контейнер, який слугує точкою входу для графа навігації в Jetpack Compose. Він пов'язує NavController з набором маршрутів і рендерить поточний екран залежно від стану back stack. За даними Android Developers (2025), NavHost є обов'язковим компонентом для будь-якого Compose-додатку з навігацією. Усередині NavHost реєструються composable-маршрути з опціональними аргументами, deep links та анімацією. Кожен маршрут — це звичайна composable-функція, яка отримує NavBackStackEntry з даними переходу. NavHost автоматично обробляє back press, збереження стану та відновлення при реконфігурації.
Головне
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().
@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(route, arguments, deepLinks, enterTransition, exitTransition, content) реєструє маршрут у графі NavHost. Параметр route — це строка, що описує шлях з опціональними плейсхолдерами виду {paramName}. Плейсхолдер замінюється на конкретне значення при навігації.
Content-блок composable отримує NavBackStackEntry, з якого витягуються аргументи. Composable-функція екрану рендериться лише тоді, коли поточний маршрут NavController збігається з route. При неспівпадінні composable видаляється з композиції, але його стан може бути збережено через rememberSaveable або ViewModel з SavedStateHandle.
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.
| Параметр маршруту | Приклад route | NavType |
|---|---|---|
| Шлях (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.
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 без слайду.
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 створює незалежний back stack, що порушує єдину навігацію. Виняток — роздільні області, наприклад, NavHost для основного контенту та NavHost для BottomSheet з власною навігацією.
NavHost — контейнер навігації, що перемикає екрани. Scaffold — макет всієї сторінки (TopAppBar, BottomNavigation, FloatingActionButton). Зазвичай NavHost розміщується всередині Scaffold.content. Scaffold не керує навігацією, а тільки надає слоти для UI-компонентів.
ViewModel створюється в рамках NavBackStackEntry через viewModel(). Для шарінгу ViewModel між екранами використовуйте parentNavController: shared ViewModel прив'яжіть до батьківського entry. Альтернатива — DI (Hilt/Koin) з scope на NavGraph.
Це нормальна поведінка — NavHost видаляє composable з композиції при виході з маршруту. Для збереження стану використовуйте rememberSaveable для UI-стану та ViewModel з SavedStateHandle для бізнес-логіки.
Додайте останній маршрут composable("404") та навігацію на нього при невідомому deep link. В NavHost немає catch-all маршруту — перевіряйте маршрут в intent-обробнику Deep Link перед navigate(). Якщо route не знайдено — navigate на 404.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також