Navigation
Dauer: 30 Minuten
- Composables als Screens
- Abhängigkeiten für Navigation hinzufügen
BottomAppBar
der App hinzufügenNavController
undNavHost
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)
}
Navigationsziele definieren
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.
Navigation aktivieren
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
Links
- Guide: https://developer.android.com/guide/navigation/navigation-3
- Sample App: https://github.com/android/nav3-recipes
- Codelab: Im Oktober 2025 keins gefunden
- Ein Codelab von 2024 zeigt die Verwendung der bisherigen Navigation vor Navigation 3: https://developer.android.com/codelabs/jetpack-compose-navigation