NavHost adalah kontainer composable yang berfungsi sebagai titik masuk untuk graf navigasi di Jetpack Compose. Ia menghubungkan NavController dengan sekumpulan rute dan me-render layar saat ini berdasarkan status back stack. Menurut Android Developers (2025), NavHost adalah komponen wajib untuk setiap aplikasi Compose dengan navigasi. Di dalam NavHost, rute composable didaftarkan dengan argumen opsional, deep links, dan animasi. Setiap rute adalah fungsi composable biasa yang menerima NavBackStackEntry dengan data transisi. NavHost secara otomatis menangani back press, penyimpanan status, dan pemulihan saat rekonfigurasi.
Poin Penting
NavHost adalah fungsi composable yang menyediakan kontainer untuk menampilkan layar navigasi saat ini. NavHost menerima NavController, startDestination, dan graf rute yang dibangun melalui Kotlin DSL. Saat rute saat ini berubah, NavHost mengganti composable yang ditampilkan dengan animasi yang ditentukan.
NavHost bekerja sebagai pengalih layar: ia melacak NavBackStackEntry saat ini dari NavController dan me-render blok composable yang sesuai. Setiap layar adalah fungsi composable independen yang menerima NavBackStackEntry dengan argumen rute. Semua layar ada dalam satu pohon komposisi, tetapi NavHost hanya menampilkan satu pada satu waktu, menyembunyikan yang lain melalui animasi.
Tidak seperti FragmentManager, NavHost tidak membuat Fragment untuk setiap layar. Seluruh siklus hidup dikelola melalui CompositionLifecycle — fungsi composable tidak memiliki onStart/onResume, sehingga untuk side-effects digunakan LaunchedEffect dan DisposableEffect. NavHost secara otomatis berlangganan ke NavController dan mengomposisi ulang UI saat rute berubah.
Menurut Google, NavHost adalah API stabil sejak Navigation 2.4.0. Mulai versi 2.8.0, NavHost mendukung Type-Safe Navigation melalui Kotlin Serialization, yang menggantikan route string dengan data class. NavHost juga mendukung graf bersarang, memungkinkan pengorganisasian navigasi per modul.
NavHost dibuat dengan dua parameter wajib: navController (instance NavHostController) dan startDestination (string rute layar pertama). Parameter ketiga — blok builder, di mana semua rute didaftarkan melalui composable(), navigation(), dan dialog().
@Composable
fun AppNavHost(navController: NavHostController) {
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") { HomeScreen(navController) }
composable("settings") { SettingsScreen(navController) }
}
}
startDestination adalah rute yang dibuka saat NavHost pertama kali dijalankan. Jika back stack kosong, NavHost secara otomatis menambahkan startDestination ke tumpukan. Saat rekonfigurasi (rotasi layar), NavHost memulihkan rute terakhir dari savedState, bukan startDestination.
Untuk BottomNavigation, startDestination adalah salah satu rute panel bawah. Rute panel lainnya ditambahkan sebagai entri composable terpisah. NavHost harus ditempatkan di dalam Scaffold.content — tempat konten utama aplikasi ditampilkan. NavHost menempati seluruh tinggi yang tersedia setelah dikurangi TopAppBar dan BottomNavigation.
Fungsi composable(route, arguments, deepLinks, enterTransition, exitTransition, content) mendaftarkan rute di graf NavHost. Parameter route adalah string yang mendeskripsikan jalur dengan placeholder opsional berbentuk {paramName}. Placeholder diganti dengan nilai konkret saat navigasi.
Blok content menerima NavBackStackEntry dari mana argumen diekstrak. Fungsi composable layar hanya di-render ketika rute NavController saat ini cocok dengan route. Jika tidak cocok, composable dihapus dari komposisi, tetapi statusnya dapat disimpan melalui rememberSaveable atau ViewModel dengan 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)
}
Jumlah entri composable di dalam NavHost bisa berapa saja — dari beberapa hingga ratusan. Untuk aplikasi besar, rute dibagi per modul dan dihubungkan melalui graf bersarang. Setiap composable dapat memiliki pengaturan animasi, deep links, dan argumen sendiri.
Argumen rute ditentukan melalui parameter arguments: List<NamedNavArgument> di composable(). Setiap argumen ditentukan melalui navArgument(name) { type; defaultValue }. NavType menentukan tipe argumen: StringType, IntType, LongType, FloatType, BoolType, ParcelableType, dan ReferenceType.
| Parameter Rute | Contoh route | NavType |
|---|---|---|
| Jalur (path) | "user/{id}" | NavType.IntType |
| Kueri (query) | "search?q={query}" | NavType.StringType |
| Opsional | "details/{id}?tab={tab}" | StringType + defaultValue="" |
| Parcelable | "checkout/{order}" | NavType.ParcelableType |
Argumen diekstrak dari NavBackStackEntry melalui arguments?.getInt("id"). Untuk argumen wajib, defaultValue dapat dihilangkan — NavType akan menggunakan null. Untuk argumen opsional, defaultValue wajib ada, jika tidak navigasi akan melempar pengecualian saat parameter tidak ada.
Sejak Navigation 2.8.0, Type-Safe Navigation direkomendasikan: tentukan sealed class atau data class untuk rute dengan Kotlin Serialization. Alih-alih route string, gunakan composable<RouteType> { backStackEntry -> }. Ini menghilangkan kesalahan ketik di route dan secara otomatis menghasilkan NavType untuk argumen. Untuk migrasi, tambahkan dependensi navigation-compose-typesafe dan plugin Kotlin Serialization.
nested graphs — mekanisme pengelompokan rute di dalam NavHost melalui fungsi navigation(route, startDestination). Graf bersarang memiliki prefiks route dan startDestination sendiri, dan semua rutenya dapat diakses melalui prefiks. nested graphs digunakan untuk arsitektur modular, di mana setiap modul fitur mendaftarkan subgrafnya sendiri.
Keuntungan graf bersarang: isolasi rute di dalam modul, back stack seragam untuk grup layar, kemampuan navigasi berdasarkan prefiks tanpa mengungkap struktur internal. Misalnya, graf "auth" berisi "auth/login" dan "auth/register". Navigasi dimungkinkan baik melalui rute lengkap maupun melalui prefiks dengan pengalihan ke 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 mendukung transmisi argumen di tingkat graf: parameter yang dideklarasikan di route graf diteruskan ke semua rute internal. Untuk membersihkan graf bersarang, gunakan popBackStack(route) — ini akan menghapus semua entri internal. Graf bersarang tidak memiliki batasan kedalaman, tetapi disarankan tidak lebih dari 3 tingkat untuk keterbacaan.
NavHost mendukung animasi transisi antar rute composable melalui parameter enterTransition, exitTransition, popEnterTransition, dan popExitTransition. Animasi ditentukan sekali untuk NavHost dan diterapkan ke semua rute, atau secara individual untuk setiap composable. Secara default, animasi dinonaktifkan.
Konfigurasi tipikal: enterTransition = slideInHorizontally(initialOffsetX = { it }) — layar masuk dari kanan; exitTransition = slideOutHorizontally(targetOffsetX = { -it }) — layar keluar ke kiri. Untuk animasi pop, arahnya berlawanan: layar masuk dari kiri dan keluar ke kanan. Untuk BottomNavigation, digunakan fadeIn/fadeOut tanpa slide.
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 */ }
Animasi kustom dibuat melalui Compose Animation API: AnimatedContentTransitionScope menyediakan akses ke dimensi kontainer, progres animasi, dan direction. Untuk shared element transition (satu elemen bertransisi mulus ke layar lain) diperlukan pustaka Accompanist Navigation Animation atau implementasi kustom melalui sharedElement Modifier. Menurut Android Developers (2025), animasi slide default (masuk dari kanan, keluar ke kiri) digunakan di 80% aplikasi Android dengan navigasi.
Pertanyaan yang Sering Diajukan
Secara teknis ya, tetapi tidak disarankan. Setiap NavHost membuat back stack independen, yang merusak navigasi terpadu. Pengecualian — area terpisah, misalnya NavHost untuk konten utama dan NavHost untuk BottomSheet dengan navigasi sendiri.
NavHost — kontainer navigasi yang mengganti layar. Scaffold — tata letak seluruh halaman (TopAppBar, BottomNavigation, FloatingActionButton). Biasanya NavHost ditempatkan di dalam Scaffold.content. Scaffold tidak mengelola navigasi, hanya menyediakan slot untuk komponen UI.
ViewModel dibuat dalam lingkup NavBackStackEntry melalui viewModel(). Untuk berbagi ViewModel antar layar, gunakan parentNavController: ViewModel bersama diikat ke entry induk. Alternatif — DI (Hilt/Koin) dengan cakupan NavGraph.
Ini adalah perilaku normal — NavHost menghapus composable dari komposisi saat meninggalkan rute. Untuk mempertahankan status, gunakan rememberSaveable untuk status UI dan ViewModel dengan SavedStateHandle untuk logika bisnis.
Tambahkan rute terakhir composable("404") dan navigasi ke sana saat deep link tidak dikenal. NavHost tidak memiliki rute catch-all — periksa rute di intent-handler Deep Link sebelum navigate(). Jika route tidak ditemukan — navigate ke 404.
Kesimpulan
Kami akan mengembangkan aplikasi seluler turnkey
IT Sectr membuat aplikasi iOS dan Android untuk startup dan bisnis sejak 2017. Kami akan memberi saran dan mengusulkan solusi terbaik.
Baca juga