NavHost — co to jest, budowa grafu i trasy w Jetpack Compose

Autor: IT Sectr Opublikowano: 2026-06-30 Czas czytania: 7 min

NavHost to kontener composable, który służy jako punkt wejścia dla grafu nawigacyjnego w Jetpack Compose. Łączy NavController z zestawem tras i renderuje bieżący ekran w zależności od stanu back stack. Według Android Developers (2025), NavHost jest obowiązkowym komponentem każdej aplikacji Compose z nawigacją. Wewnątrz NavHost rejestrowane są trasy composable z opcjonalnymi argumentami, deep links i animacją. Każda trasa to zwykła funkcja composable, która otrzymuje NavBackStackEntry z danymi przejścia. NavHost automatycznie obsługuje back press, zapisywanie stanu i przywracanie przy rekonfiguracji.

Najważniejsze

  • NavHost — kontener composable łączący NavController z grafem tras i renderujący bieżący ekran
  • composable() — funkcja rejestracji trasy z route, argumentami, deep links i animacją przejść
  • startDestination — początkowa trasa otwierana przy tworzeniu NavHost
  • Argumenty definiowane przez navArgument z NavType dla typowanego przesyłania danych między ekranami
  • Animacja konfigurowana globalnie lub indywidualnie przez parametry enterTransition, exitTransition

Czym jest NavHost w Jetpack Compose?

NavHost — to funkcja composable zapewniająca kontener do wyświetlania bieżącego ekranu nawigacji. NavHost przyjmuje NavController, startDestination i graf tras zbudowany przez Kotlin DSL. Po zmianie bieżącej trasy NavHost przełącza wyświetlany composable z zadaną animacją.

NavHost działa jak przełącznik ekranów: śledzi bieżący NavBackStackEntry z NavController i renderuje odpowiedni blok composable. Każdy ekran to niezależna funkcja composable, która otrzymuje NavBackStackEntry z argumentami trasy. Wszystkie ekrany istnieją w jednym drzewie kompozycji, ale NavHost pokazuje tylko jeden na raz, ukrywając pozostałe przez animację.

W przeciwieństwie do FragmentManager, NavHost nie tworzy Fragment dla każdego ekranu. Cały lifecycle jest zarządzany przez CompositionLifecycle — funkcje composable nie mają onStart/onResume, dlatego do side-efektów używa się LaunchedEffect i DisposableEffect. NavHost automatycznie subskrybuje NavController i przebudowuje UI przy zmianie trasy.

Według Google, NavHost jest stable API od wersji Navigation 2.4.0. Od wersji 2.8.0 NavHost obsługuje Type-Safe Navigation przez Kotlin Serialization, co zastępuje stringowe route na data-klasy. NavHost obsługuje również zagnieżdżone grafy, co pozwala organizować nawigację po modułach.

NavHost jest tworzony z dwoma obowiązkowymi parametrami: navController (instancja NavHostController) i startDestination (string trasy pierwszego ekranu). Trzeci parametr — builder-block, w którym rejestruje się wszystkie trasy przez composable(), navigation() i dialog().

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

startDestination — to trasa otwierana przy pierwszym uruchomieniu NavHost. Jeśli back stack jest pusty, NavHost automatycznie dodaje startDestination do stosu. Przy rekonfiguracji (obrót ekranu) NavHost przywraca ostatnią trasę z savedState, a nie startDestination.

Dla BottomNavigation startDestination to jedna z tras dolnego panelu. Pozostałe trasy panelu są dodawane jako osobne wpisy composable. NavHost powinien być umieszczony wewnątrz Scaffold.content — tam, gdzie wyświetlana jest główna treść aplikacji. NavHost zajmuje całą dostępną wysokość pomniejszoną o TopAppBar i BottomNavigation.

Rejestracja tras przez composable

Funkcja composable(route, arguments, deepLinks, enterTransition, exitTransition, content) rejestruje trasę w grafie NavHost. Parametr route to string opisujący ścieżkę z opcjonalnymi placeholderami w postaci {paramName}. Placeholder jest zastępowany konkretną wartością podczas nawigacji.

Content-block composable otrzymuje NavBackStackEntry, z którego wydobywane są argumenty. Funkcja composable ekranu jest renderowana tylko wtedy, gdy bieżąca trasa NavController pasuje do route. W przypadku niezgodności composable jest usuwany z kompozycji, ale jego stan może być zachowany przez rememberSaveable lub ViewModel z 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)
}

Liczba wpisów composable wewnątrz NavHost może być dowolna — od kilku do setek. Dla dużych aplikacji trasy są dzielone na moduły i podłączane przez zagnieżdżone grafy. Każdy composable może mieć własne ustawienia animacji, deep links i argumentów.

Argumenty i typowane parametry tras

Argumenty trasy są definiowane przez parametr arguments: List<NamedNavArgument> w composable(). Każdy argument jest określany przez navArgument(name) { type; defaultValue }. NavType określa typ argumentu: StringType, IntType, LongType, FloatType, BoolType, ParcelableType i ReferenceType.

Parametr trasyPrzykład routeNavType
Ścieżka (path)„user/{id}"NavType.IntType
Zapytanie (query)„search?q={query}"NavType.StringType
Opcjonalny„details/{id}?tab={tab}"StringType + defaultValue=""
Parcelable„checkout/{order}"NavType.ParcelableType

Argumenty są wydobywane z NavBackStackEntry przez arguments?.getInt("id"). Dla obowiązkowych argumentów defaultValue może być pominięty — NavType będzie używać null. Dla opcjonalnych argumentów defaultValue jest wymagany, w przeciwnym razie nawigacja wyrzuci wyjątek przy braku parametru.

Od wersji Navigation 2.8.0 zalecany jest Type-Safe Navigation: zdefiniuj sealed class lub data class dla tras z Kotlin Serialization. Zamiast stringowego route używaj composable<RouteType> { backStackEntry -> }. Eliminuje to literówki w route i automatycznie generuje NavType dla argumentów. Do migracji dodaj zależność navigation-compose-typesafe i plugin Kotlin Serialization.

Zagnieżdżone grafy nawigacji

nested graphs — mechanizm grupowania tras wewnątrz NavHost przez funkcję navigation(route, startDestination). Zagnieżdżony graf ma własny prefiks route i startDestination, a wszystkie jego trasy są dostępne przez prefiks. nested graphs są używane w architekturze modułowej, gdzie każdy moduł feature rejestruje swój podgraf.

Zalety zagnieżdżonych grafów: izolacja tras wewnątrz modułu, jednolity back stack dla grupy ekranów, możliwość nawigacji po prefiksie bez ujawniania wewnętrznej struktury. Na przykład graf „auth" zawiera „auth/login" i „auth/register". Nawigacja jest możliwa zarówno po pełnej trasie, jak i po prefiksie z przekierowaniem na 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 obsługują przekazywanie argumentów na poziomie grafu: parametry zadeklarowane w route grafu są przekazywane do wszystkich wewnętrznych tras. Do czyszczenia zagnieżdżonego grafu użyj popBackStack(route) — usunie wszystkie wewnętrzne wpisy. Zagnieżdżone grafy nie mają ograniczenia głębokości, ale zaleca się nie więcej niż 3 poziomy dla czytelności.

Animacja i personalizacja przejść

NavHost obsługuje animację przejść między trasami composable przez parametry enterTransition, exitTransition, popEnterTransition i popExitTransition. Animacje są definiowane raz dla NavHost i stosowane do wszystkich tras, albo indywidualnie dla każdego composable. Domyślnie animacja jest wyłączona.

Typowa konfiguracja: enterTransition = slideInHorizontally(initialOffsetX = { it }) — ekran wjeżdża z prawej; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — ekran wyjeżdża w lewo. Dla animacji pop kierunki są lustrzane: ekran wjeżdża z lewej i wyjeżdża w prawo. Dla BottomNavigation używane jest fadeIn/fadeOut bez slide.

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 */ }

Niestandardowe animacje są tworzone przez Compose Animation API: AnimatedContentTransitionScope zapewnia dostęp do rozmiarów kontenera, postępu animacji i direction. Dla shared element transition (jeden element płynnie przechodzi na inny ekran) wymagana jest biblioteka Accompanist Navigation Animation lub niestandardowa implementacja przez sharedElement Modifier. Według Android Developers (2025), animacja slide domyślnie (wjazd z prawej, wyjazd w lewo) jest używana w 80% aplikacji Android z nawigacją.

Często zadawane pytania

Czy można używać wielu NavHost w jednym Activity?

Technicznie tak, ale nie jest zalecane. Każdy NavHost tworzy niezależny back stack, co narusza jednolitą nawigację. Wyjątkiem są oddzielne obszary, np. NavHost dla głównej treści i NavHost dla BottomSheet z własną nawigacją.

Czym różni się NavHost od Scaffold w Compose?

NavHost — kontener nawigacji przełączający ekrany. Scaffold — układ całej strony (TopAppBar, BottomNavigation, FloatingActionButton). Zazwyczaj NavHost jest umieszczany wewnątrz Scaffold.content. Scaffold nie zarządza nawigacją, a jedynie udostępnia sloty dla komponentów UI.

Jak przekazać ViewModel między ekranami przez NavHost?

ViewModel jest tworzony w ramach NavBackStackEntry przez viewModel(). Do współdzielenia ViewModel między ekranami użyj parentNavController: shared ViewModel podłącz do nadrzędnego entry. Alternatywą jest DI (Hilt/Koin) z zakresem NavGraph.

Dlaczego NavHost odtwarza composable przy każdym przejściu?

To normalne zachowanie — NavHost usuwa composable z kompozycji przy opuszczeniu trasy. Do zachowania stanu używaj rememberSaveable dla stanu UI i ViewModel z SavedStateHandle dla logiki biznesowej.

Jak dodać obsługę 404 (nieznana trasa) w NavHost?

Dodaj ostatnią trasę composable("404") i nawigację do niej przy nieznanym deep link. W NavHost nie ma catch-all trasy — sprawdzaj trasę w intent-handlerze Deep Link przed navigate(). Jeśli route nie znaleziono — navigate na 404.

Podsumowanie

  • NavHost — kontener composable Navigation Compose, łączący NavController z grafem tras i renderujący bieżący ekran
  • composable() rejestruje trasę z route, argumentami (NavType), deep links i animacją
  • startDestination — początkowa trasa otwierana przy pierwszym uruchomieniu NavHost
  • Argumenty są przekazywane przez placeholdery {param} z NavType dla typowania i defaultValue dla opcjonalnych parametrów
  • Zagnieżdżone grafy przez navigation() pozwalają grupować trasy według modułów z izolowanym back stack
  • Animacja przejść konfigurowana przez enterTransition/exitTransition z użyciem Compose Animation API
  • NavHost automatycznie obsługuje back press, zapisywanie stanu i deep links bez dodatkowego kodu

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również