Skip to Content

Navigation

Dauer: 30 Minuten

  • Composables als Screens
  • Abhängigkeiten für Navigation hinzufügen
  • BottomAppBar der App hinzufügen
  • NavController und NavHost in Compose
  • Navigation in BottomAppBar

Ziel: Erste Schritte mit Navigation in Compose

Neue Navigation 3: https://developer.android.com/guide/navigation/navigation-3 

Vorbemerkung: Im Oktober 2025 war Navigation 3 noch im Alpha-Stadium, d.h. die API kann sich noch ändern.

Abhängigkeiten für Navigation hinzufügen

Versionskatalog libs.versions.toml erweitern:

[versions] # Rest bleibt unverändert nav3Core = "1.0.0-alpha10" kotlinSerialization = "2.2.20" [libraries] # Rest bleibt unverändert androidx-navigation3-runtime = { module = "androidx.navigation3:navigation3-runtime", version.ref = "nav3Core" } androidx-navigation3-ui = { module = "androidx.navigation3:navigation3-ui", version.ref = "nav3Core" } [plugins] # Rest bleibt unverändert jetbrains-kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlinSerialization"}

app/build.gradle.kts anpassen:

plugins { // Rest bleibt unverändert alias(libs.plugins.jetbrains.kotlin.serialization) } // Rest bleibt unverändert dependencies { // Rest bleibt unverändert implementation(libs.androidx.navigation3.ui) implementation(libs.androidx.navigation3.runtime) }

Wir werden in unserer App eine Navigationsleiste am unteren Rand erstellen. Dazu bereiten wir zunächst die Navigationsziele vor, die in der Leiste angezeigt werden sollen. In MainActivity.kt fügen wir oberhalb der MainActivity-Klasse folgenden Code hinzu:

interface BottomNavItem { val icon: Int val title: String } @Serializable data object Home : NavKey, BottomNavItem { override val icon = R.drawable.home_24px override val title = "Home" } @Serializable data object Settings : NavKey, BottomNavItem { override val icon = R.drawable.settings_24px override val title: String = "Einstellungen" }

Für die beiden Icons müssen wir wieder die XML-Ressourcen herunterladen (https://fonts.google.com/icons ) und im Resource Manager einfügen (siehe Floating Action Button).

Bottom Navigation Bar im Scaffold

Das Scaffold-Composable bietet die Möglichkeit, eine BottomBar zu definieren:

@Composable fun TodosApp(vm: TodosViewModel) { val todos = vm.todos var showDialog by remember { mutableStateOf(false) } TodosAndroid2025Theme { val bottomNavItems = listOf(Home, Settings) Scaffold( bottomBar = { NavigationBar { bottomNavItems.forEach { item -> NavigationBarItem( selected = false, // TODO, onClick = { /*TODO*/ }, icon = { Icon( imageVector = ImageVector.vectorResource(item.icon), contentDescription = item.title ) }, label = { Text(item.title) } ) } } }, floatingActionButton = { // Rest bleibt unverändert } ) } }

Es werden die beiden Navigationsziele Home und Settings in der BottomBar angezeigt.

Es muss ein BackStack implementiert werden und ein NavDisplay kümmert sich um die eigentliche Navigation.

Da Navigation 3 erst im Mai 2025 vorgestellt wurde und sich sicherlich noch ändern wird, stellen wir hier nur einen minimalen Code zur Verfügung, der als Ausgangspunkt dienen kann.

Die wesentlichen Änderungen betreffen TodosApp in MainActivity.kt:

@Composable fun TodosApp(vm: TodosViewModel) { val todos = vm.todos var showDialog by remember { mutableStateOf(false) } // Tabs val bottomNavItems = remember { listOf(Home, Settings) } // Je Tab ein eigener, zustandssicherer Backstack val homeStack = rememberNavBackStack(Home) val settingsStack = rememberNavBackStack(Settings) // Aktueller Tab var current: BottomNavItem by remember { mutableStateOf<BottomNavItem>(Home) } // Sichtbarer Backstack für NavDisplay val visible = remember { mutableStateListOf<NavKey>().apply { addAll(homeStack) } // Home ist Start → nicht leer } // Sichtbaren Stack synchron halten (StartStack + CurrentStack) LaunchedEffect(Unit) { snapshotFlow { Triple(current, homeStack.toList(), settingsStack.toList()) } .collect { (sel, home, settings) -> visible.clear() if (sel == Home) { visible.addAll(home) } else { visible.addAll(home + settings) } } } TodosAndroid2025Theme { Scaffold( bottomBar = { NavigationBar { bottomNavItems.forEach { item -> val selected = current == item NavigationBarItem( selected = selected, onClick = { current = item }, icon = { Icon( imageVector = ImageVector.vectorResource(item.icon), contentDescription = item.title ) }, label = { Text(item.title) } ) } } }, floatingActionButton = { FloatingActionButton( onClick = { showDialog = true }, ) { Icon( painter = painterResource(R.drawable.add_24px), contentDescription = "Neues Todo erstellen" ) } }) { innerPadding -> if (showDialog) { AddTodoDialog( onAdd = { text -> vm.add(text) showDialog = false }, onDismiss = { showDialog = false } ) } NavDisplay( backStack = visible, onBack = { val active = if (current == Home) homeStack else settingsStack when { active.size > 1 -> active.removeLastOrNull() current != Home -> current = Home else -> Unit } }, entryProvider = entryProvider { entry<Home> { TodoList( todos = todos, onToggleAt = vm::toggleAt, modifier = Modifier.padding(innerPadding) ) } entry<Settings> { Text("Einstellungen", modifier = Modifier.padding(innerPadding) ) } } ) } } }

In diesem Video zu Bottom Navigation vom 31.05.2025 ist ein alternativer Ansatz zu finden: https://www.youtube.com/watch?v=7Pv5MQEdw54 

Nächste Schritte

  • FAB nur in Home-Screen anzeigen