NavHost is een composable-container die fungeert als toegangspunt voor de navigatiegraaf in Jetpack Compose. Het verbindt NavController met een set routes en rendert het huidige scherm op basis van de back stack-status. Volgens Android Developers (2025) is NavHost een verplichte component voor elke Compose-app met navigatie. Binnen NavHost worden composable-routes geregistreerd met optionele argumenten, deep links en animatie. Elke route is een gewone composable-functie die NavBackStackEntry met overgangsgegevens ontvangt. NavHost verwerkt automatisch back press, statusopslag en herstel bij reconfiguratie.
Belangrijkste punten
NavHost is een composable-functie die een container biedt voor het weergeven van het huidige navigatiescherm. NavHost accepteert NavController, startDestination en de routegraaf die via Kotlin DSL is opgebouwd. Bij het wijzigen van de huidige route schakelt NavHost de weergegeven composable met de opgegeven animatie.
NavHost werkt als een schermschakelaar: het volgt de huidige NavBackStackEntry van NavController en rendert het bijbehorende composable-blok. Elk scherm is een onafhankelijke composable-functie die NavBackStackEntry met routeargumenten ontvangt. Alle schermen bestaan in dezelfde compositieboom, maar NavHost toont er slechts één tegelijk, waarbij de andere via animatie worden verborgen.
In tegenstelling tot FragmentManager maakt NavHost geen Fragment voor elk scherm. De hele levenscyclus wordt beheerd via CompositionLifecycle — composable-functies hebben geen onStart/onResume, dus voor bijwerkingen worden LaunchedEffect en DisposableEffect gebruikt. NavHost abonneert zich automatisch op NavController en herstelt de UI bij routewijziging.
Volgens Google is NavHost een stabiele API sinds Navigation 2.4.0. Vanaf 2.8.0 ondersteunt NavHost Type-Safe Navigation via Kotlin Serialization, wat string-routes vervangt door data-klassen. NavHost ondersteunt ook geneste grafen, wat navigatie per module mogelijk maakt.
NavHost wordt gemaakt met twee verplichte parameters: navController (NavHostController-instantie) en startDestination (string van de eerste schermroute). De derde parameter is het builder-blok waarin alle routes worden geregistreerd via composable(), navigation() en dialog().
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") { HomeScreen(navController) }
composable("settings") { SettingsScreen(navController) }
}
}
startDestination is de route die wordt geopend bij de eerste start van NavHost. Als de back stack leeg is, voegt NavHost automatisch startDestination toe aan de stapel. Bij reconfiguratie (schermrotatie) herstelt NavHost de laatste route uit savedState, niet startDestination.
Voor BottomNavigation is startDestination een van de routes van het onderste paneel. De overige routes van het paneel worden als afzonderlijke composable-items toegevoegd. NavHost moet worden geplaatst in Scaffold.content — waar de hoofdinhoud van de app wordt weergegeven. NavHost beslaat de volledige beschikbare hoogte minus TopAppBar en BottomNavigation.
De functie composable(route, arguments, deepLinks, enterTransition, exitTransition, content) registreert een route in de NavHost-graaf. De parameter route is een string die het pad beschrijft met optionele placeholders in de vorm {paramName}. De placeholder wordt bij navigatie vervangen door een concrete waarde.
Het content-blok ontvangt NavBackStackEntry waaruit argumenten worden gehaald. De composable-functie van het scherm wordt alleen weergegeven wanneer de huidige NavController-route overeenkomt met route. Bij niet-overeenkomst wordt de composable uit de compositie verwijderd, maar de status kan worden opgeslagen via rememberSaveable of ViewModel met 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)
}
Het aantal composable-items in NavHost kan variëren van een paar tot honderden. Voor grote apps worden routes opgedeeld in modules en verbonden via geneste grafen. Elke composable kan eigen animatie-, deep link- en argumentinstellingen hebben.
Routeargumenten worden gedefinieerd via de parameter arguments: List<NamedNavArgument> in composable(). Elk argument wordt opgegeven via navArgument(name) { type; defaultValue }. NavType bepaalt het argumenttype: StringType, IntType, LongType, FloatType, BoolType, ParcelableType en ReferenceType.
| Routeparameter | Voorbeeld route | NavType |
|---|---|---|
| Pad (path) | „user/{id}" | NavType.IntType |
| Query | „search?q={query}" | NavType.StringType |
| Optioneel | „details/{id}?tab={tab}" | StringType + defaultValue="" |
| Parcelable | „checkout/{order}" | NavType.ParcelableType |
Argumenten worden uit NavBackStackEntry gehaald via arguments?.getInt("id"). Voor verplichte argumenten kan defaultValue ontbreken — NavType gebruikt dan null. Voor optionele argumenten is defaultValue verplicht, anders gooit navigatie een uitzondering bij afwezigheid van de parameter.
Sinds Navigation 2.8.0 wordt Type-Safe Navigation aanbevolen: definieer een sealed class of data class voor routes met Kotlin Serialization. Gebruik in plaats van string-route composable<RouteType> { backStackEntry -> }. Dit elimineert typefouten in route en genereert automatisch NavType voor argumenten. Voor migratie voegt u de afhankelijkheid navigation-compose-typesafe en de Kotlin Serialization-plugin toe.
nested graphs — mechanisme voor het groeperen van routes in NavHost via de functie navigation(route, startDestination). Een geneste graaf heeft een eigen route-prefix en startDestination, en al zijn routes zijn toegankelijk via de prefix. nested graphs worden gebruikt voor modulaire architectuur, waarbij elke feature-module zijn eigen subgraaf registreert.
Voordelen van geneste grafen: isolatie van routes binnen de module, uniforme back stack voor een groep schermen, navigatie op prefix zonder interne structuur bloot te geven. Bijvoorbeeld, de graaf „auth" bevat „auth/login" en „auth/register". Navigatie is mogelijk via het volledige routepad of via prefix met omleiding naar 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 ondersteunen het doorgeven van argumenten op graafniveau: parameters gedeclareerd in het routepad van de graaf worden doorgegeven aan alle interne routes. Gebruik popBackStack(route) om een geneste graaf te wissen — het verwijdert alle interne items. Geneste grafen hebben geen dieptebeperking, maar voor leesbaarheid wordt maximaal 3 niveaus aanbevolen.
NavHost ondersteunt overgangsanimatie tussen composable-routes via de parameters enterTransition, exitTransition, popEnterTransition en popExitTransition. Animaties worden één keer voor NavHost gedefinieerd en toegepast op alle routes, of individueel voor elke composable. Standaard is animatie uitgeschakeld.
Typische configuratie: enterTransition = slideInHorizontally(initialOffsetX = { it }) — het scherm komt van rechts binnen; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — het scherm verdwijnt naar links. Voor pop-animatie zijn de richtingen gespiegeld: het scherm komt van links binnen en verdwijnt naar rechts. Voor BottomNavigation wordt fadeIn/fadeOut zonder slide gebruikt.
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 */ }
Custom animaties worden gemaakt via de Compose Animation API: AnimatedContentTransitionScope biedt toegang tot containerafmetingen, animatievoortgang en direction. Voor shared element transition (een element dat soepel naar een ander scherm overgaat) is de Accompanist Navigation Animation-bibliotheek of een custom implementatie via sharedElement Modifier vereist. Volgens Android Developers (2025) wordt de standaard slide-animatie (binnenkomst van rechts, vertrek naar links) gebruikt in 80% van de Android-apps met navigatie.
Veelgestelde vragen
Technisch gezien wel, maar het wordt afgeraden. Elke NavHost creëert een onafhankelijke back stack, wat de eenheid van navigatie verbreekt. Uitzondering zijn gescheiden gebieden, zoals een NavHost voor hoofdinhoud en een NavHost voor BottomSheet met eigen navigatie.
NavHost — navigatiecontainer die schermen schakelt. Scaffold — lay-out van de hele pagina (TopAppBar, BottomNavigation, FloatingActionButton). Meestal wordt NavHost in Scaffold.content geplaatst. Scaffold beheert geen navigatie, maar biedt alleen slots voor UI-componenten.
ViewModel wordt gemaakt binnen NavBackStackEntry via viewModel(). Voor het delen van ViewModel tussen schermen gebruikt u parentNavController: koppel de gedeelde ViewModel aan de bovenliggende entry. Alternatief — DI (Hilt/Koin) met scope op NavGraph.
Dit is normaal gedrag — NavHost verwijdert de composable uit de compositie bij het verlaten van een route. Gebruik rememberSaveable voor UI-status en ViewModel met SavedStateHandle voor bedrijfslogica om de status te behouden.
Voeg de laatste route composable("404") toe en navigeer ernaar bij een onbekende deep link. NavHost heeft geen catch-all route — controleer de route in de Deep Link intent-handler vóór navigate(). Als route niet wordt gevonden — navigeer naar 404.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook