NavController — podstata, metody a řízení navigace v Jetpack Compose

Autor: IT Sectr Publikováno: 2026-06-29 Doba čtení: 7 min

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 — centrální ovladač navigace Compose, řídí back stack a přechody mezi obrazovkami
  • navigate() — hlavní metoda pro přechod na trasu s podporou NavOptions pro správu zásobníku
  • popBackStack() — návrat na předchozí obrazovku s volitelným vyčištěním až k zadané trase
  • SavedStateHandle — integrace s ViewModel pro ukládání stavu obrazovky při navigaci
  • currentBackStackEntryAsState() — sledování aktuální trasy pro synchronizaci UI

Co je NavController v Jetpack Compose?

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.

kotlin
@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.

kotlin
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: řízení návratu a čištění zásobníku

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.

MetodaPopisPříklad
popBackStack()Návrat o jednu obrazovku zpětnavController.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ímnavigate("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: ukládání stavu obrazovky

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.

kotlin
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.

Sledování aktuální trasy pomocí currentBackStackEntryAsState

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.

kotlin
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

Lze vytvořit více NavController v jednom Activity?

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).

Jak předat NavController prostřednictvím ViewModel?

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.

Proč navigate nefunguje po asynchronní operaci?

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.

Jak vyčistit celý back stack a přejít na novou obrazovku?

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.

Čím se liší NavHostController od NavController?

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

  • NavController — centrální komponenta Navigation Compose, řídí zásobník tras a přechody mezi obrazovkami
  • navigate() provádí přechod s nastavením popUpTo, launchSingleTop a restoreState prostřednictvím NavOptions
  • popBackStack() řídí návrat: jeden krok nebo hromadné čištění až k zadané trase s inclusive
  • SavedStateHandle se integruje s ViewModel pro automatické ukládání stavu obrazovky při navigaci
  • currentBackStackEntryAsState() poskytuje reaktivní sledování aktuální trasy pro synchronizaci UI
  • BackHandler zpracovává systémové tlačítko Back, PredictiveBackGesture je podporováno od NavController 2.9.0
  • Pro testování použijte TestNavHostController s compose-test-rule a matchery Semantics

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í.

Prodiskutovat projekt

Přečtěte si také