NavController je centrální komponenta knihovny Navigation Compose, která řídí navigační zásobník a stav back stack v aplikacích pro Android. Prostřednictvím NavController se provádí přechody mezi obrazovkami, návrat na předchozí stránky a předávání dat mezi trasami. Podle Android Developers (2025) je NavController povinným prvkem každé aplikace Compose s více než jednou obrazovkou. Ovladač se vytváří pomocí rememberNavController(), předává se do NavHost a je k dispozici pro volání navigate() z libovolného místa kompozice. Vestavěná podpora SavedStateHandle automaticky ukládá stav ViewModel při rekonfiguraci.
Hlavní body
NavController — je třída z knihovny Navigation Compose, která implementuje ovladač navigace pro aplikace Compose. NavController spravuje zásobník NavBackStackEntry, kde každý záznam obsahuje trasu, argumenty a stav obrazovky. Ovladač podporuje základní navigační operace: přechod, návrat, nahrazení a čištění.
Na rozdíl od systému View, kde navigace probíhala prostřednictvím FragmentManager nebo Intent, NavController pracuje výhradně v kontextu Compose. Back stack je uložen jako graf NavDestination, nikoli jako zásobník Fragment. Tím se eliminuje režie vytváření a ničení Fragment a také se zjednodušuje testování — NavController lze mockovat pomocí TestNavHostController.
NavController je úzce spojen s NavHost — kontejnerem, který vykresluje aktuální obrazovku z grafu. Bez NavHost nemůže NavController zobrazovat composable funkce, ale zachovává schopnost řídit zásobník. V typické architektuře je NavController vytvářen na úrovni Activity nebo hlavního composable a předáván dolů stromem kompozice prostřednictvím parametrů.
Podle Google prošel NavController několika hlavními verzemi. Verze 2.8.0 přidala Type-Safe Navigation, verze 2.9.0 — podporu predictive back gesture (Android 14+). Ovladač je kompatibilní s Material3 Scaffold a BottomNavigation. Pro multimodulární projekty se NavController předává prostřednictvím DI (Hilt/Koin) nebo parametrů konstruktoru.
NavController se vytváří pomocí composable funkce rememberNavController(). Funkce vrací instanci NavHostController (potomka NavController) vázanou na životní cyklus aktuálního composable. Při opuštění kompozice se ovladač vymaže. Pro uložení ovladače při rekonfiguraci použijte rememberSaveable nebo ViewModel.
@Composable
fun MyApp() {
val navController = rememberNavController()
NavHost(
navController = navController,
startDestination = "main"
) {
composable("main") { MainScreen(navController) }
composable("details") { DetailsScreen(navController) }
}
}
Konfigurace NavController zahrnuje: NavHostController (hlavní), TestNavHostController (testování) a ScopedNavController (potomek pro vnořené grafy). Pro BottomNavigation by měl být NavController jedinečný pro celou aplikaci — vytvoření nového ovladače v každé záložce povede ke ztrátě zásobníku. Pro předání ovladače do vnořených obrazovek použijte parametr funkce, nikoli CompositionLocalProvider, aby byla zachována čitelnost.
Pro testování navigace použijte TestNavHostController s compose-test-rule. Ovladač umožňuje nastavit počáteční trasu a ověřit, že navigate() zavolala očekávaný přechod. Testování NavController nevyžaduje emulátor — funguje s matchery Semantics Compose Test.
Metoda navigate(route: String) — hlavní způsob navigace v NavController. Přijímá řetězec trasy, volitelné NavOptions a Navigator.Extras. NavOptions řídí chování přechodu: launchSingleTop (nezdvojovat trasu v zásobníku), popUpTo (vyčistit zásobník až k trase), restoreState (obnovit předchozí stav).
NavOptions se nastavují pomocí builder syntaxe: NavOptionsBuilder. Hlavní parametry: popUpTo (route + inclusive/saveState), launchSingleTop (Boolean, true — nevytvářet duplikát), restoreState (obnovit stav při návratu). Bez popUpTo každý navigate() přidává záznam do zásobníku, což vede k hromadění back stack a nesprávnému chování tlačítka Back.
navController.navigate("profile/42") {
popUpTo("main") { saveState = true }
launchSingleTop = true
restoreState = true
}
Navigator.Extras umožňuje předat další data, která nejsou součástí trasy: shared element pro animaci, příznaky Intent, Pac-Man bundle. Extras se používají zřídka — hlavně pro integraci s Accompanist Animation nebo vlastním Navigator. Pro většinu scénářů stačí řetězec trasy a NavOptions.
popBackStack() — metoda pro návrat na předchozí obrazovku. Bez argumentů odstraní horní záznam zásobníku a vrátí true, pokud bylo odstranění úspěšné. Pokud je zásobník prázdný — metoda vrátí false a Activity se zavře (podobně jako super.onBackPressed()).
Přetížená verze popBackStack(route: String, inclusive: Boolean) odstraní všechny záznamy až k zadané trase. Pokud inclusive = true — odstraní se i samotná zadaná trasa. Metoda vrací Boolean — true, pokud byly záznamy nalezeny a odstraněny. Verze s inclusive je užitečná pro scénáře „odchod na kořenovou obrazovku” po autorizaci nebo dokončení objednávky.
| Metoda | Popis | Příklad |
|---|---|---|
| popBackStack() | Návrat o jednu obrazovku zpět | navController.popBackStack() |
| popBackStack(route, false) | Vyčištění až k trase (trasa zůstává) | popBackStack("home", false) |
| popBackStack(route, true) | Vyčištění až k trase včetně jí | popBackStack("home", true) |
| navigate(route) { popUpTo(route) { inclusive = true } } | Přechod s úplným vyčištěním | navigate("login") { popUpTo(0) { inclusive = true } } |
Pro zpracování systémového tlačítka Back (hardware back button) použijte BackHandler z Compose. BackHandler přijímá enabled a onBack — callback volaný při stisknutí. Pro Android 14+ se používá PredictiveBackGesture, integrovaný prostřednictvím NavController od verze 2.9.0. Predictive back přidává animaci náhledu návratu.
SavedStateHandle — je mechanizmus pro ukládání stavu ViewModel při navigaci a rekonfiguraci. NavController automaticky poskytuje SavedStateHandle pro každý NavBackStackEntry. Prostřednictvím SavedStateHandle ViewModel ukládá stav obrazovky a obnovuje jej při návratu (restoreState = true).
V Navigation Compose se SavedStateHandle používá společně s ViewModel: ViewModel se inicializuje prostřednictvím SavedStateHandle, který je předán z backStackEntry. Při přechodu na jinou obrazovku a návratu (s restoreState) ViewModel obdrží uložený stav, není vytvářen znovu. To je kritické pro obrazovky se vstupem dat, filtry nebo posouváním.
class ProfileViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
val userId: String = savedStateHandle.get<String>("userId") ?: ""
var searchQuery by savedStateHandle.getStateFlow("search", "")
.collectAsState()
}
SavedStateHandle podporuje primitivní typy, String, Bundle a Parcelable. Pro složité objekty ukládejte pouze ID a kompletní data načtěte z úložiště. Limit SavedStateHandle je přibližně 1 MB, překročení způsobí TransactionTooLargeException. Pro velké objemy použijte Room nebo DataStore místo ukládání do handle.
Důležité: SavedStateHandle ukládá stav pouze při použití restoreState = true v NavOptions. Pokud restoreState není zadán, při návratu je ViewModel vytvořen znovu s výchozími hodnotami. Pro přepínání BottomNavigation s restoreState NavController ukládá stav každé záložky a obnovuje jej při opětovném výběru.
currentBackStackEntryAsState() — funkce vracející State<NavBackStackEntry?>, který se aktualizuje při každé změně aktuální trasy. To je hlavní mechanizmus synchronizace UI s navigací: BottomNavigation zvýrazňuje aktivní prvek, Toolbar aktualizuje název, Drawer se zavírá při přechodu.
Funkce pracuje prostřednictvím snapshotFlow a collectAsState: při změně back stack Compose překomponuje přihlášené prvky. Důležité: currentBackStackEntryAsState() se aktualizuje až po dokončení animace přechodu. Pro okamžitou aktualizaci použijte currentDestination, který se mění synchronně s navigate(), ale nepodporuje stav.
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
Text(
text = when (currentRoute) {
"home" -> "Home"
"profile" -> "Profile"
else -> ""
}
)
Pro přístup k argumentům aktuální trasy použijte navBackStackEntry?.arguments. To je výhodné v BottomNavigation: selectedItem se vypočítává na základě currentRoute. Pro ladění navigace použijte NavController.addOnDestinationChangedListener(), který loguje každý přechod. V produkci se vyhněte přihlášení v rámci velkého množství composable — vytvořte jeden zdroj ve ViewModel a předávejte State do UI.
Často kladené otázky
Technicky ano, ale nedoporučuje se. Jeden NavController zajišťuje konzistentní back stack a zjednodušuje ladění. Více ovladačů je ospravedlnitelné pouze pro vnořené grafy s oddělenou navigací (např. modal bottom sheet s vlastním zásobníkem).
Předávejte NavController do ViewModel prostřednictvím konstruktoru nebo DI. Je však lepší předávat pouze callback funkce (onNavigate, onBack), nikoli samotný NavController — to zjednodušuje testování. Pro události použijte Channel<NavEvent> ve ViewModel a sbírejte v UI.
Problém je v životním cyklu: pokud NavController ještě není inicializován (NavHost není sestaven), navigate() je ignorováno. Použijte LaunchedEffect pro volání navigace po načtení dat, nikoli uvnitř coroutine s libovolným lifecycle.
Zavolejte navController.navigate("target") { popUpTo(0) { inclusive = true } }. Parametr popUpTo(0) úplně vyčistí zásobník, inclusive = true odstraní i počáteční záznam. Příznak launchSingleTop = true brání duplikaci nové trasy.
NavHostController — potomek NavController s dalšími metodami pro NavHost (např. setOnBackStackChangedListener). NavController — základní třída, kterou lze používat mimo NavHost pro programové řízení zásobníku. Ve většině případů se používá NavHostController.
Souhrn
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také