BottomNavigation: Was es ist, Struktur und Einrichtung in Jetpack Compose

Autor: IT Sectr Veröffentlicht: 2026-06-29 Lesezeit: 8 Min.

BottomNavigation (NavigationBar in Material3) ist eine Material Design-Komponente, die die Navigation zwischen drei bis fünf Hauptbildschirmen einer Anwendung ermöglicht. In Jetpack Compose wird die untere Leiste über NavigationBar oder BottomNavigation implementiert, wobei jedes Element durch ein Symbol und eine Textbeschriftung dargestellt wird. Laut Google Material Design (2025) wird BottomNavigation für iOS und Android als primäres Navigationsmuster empfohlen. Das Panel passt sich automatisch an die Höhe der Systemnavigation (Gesture Navigation) über WindowInsets an. NavigationBar in Material3 unterstützt dynamische Farbe, Badge und adaptive Abstände.

Wichtige Punkte

  • BottomNavigation — untere Navigationsleiste für 3–5 Bildschirme, implementiert über NavigationBar in Material3
  • NavigationBarItem — Panel-Element mit Symbol, Beschriftung und Badge für Benachrichtigungen
  • Verbindung mit NavHost — Auswahl eines Elements löst navigate() im NavController aus, um den Graphen zu wechseln
  • Material3 fügt dynamische Farbe und automatische Systemnavigation über WindowInsets hinzu
  • Badge — Benachrichtigungs-Badge auf dem Symbol, implementiert über BadgedBox mit Zähler

Was ist BottomNavigation in Jetpack Compose?

BottomNavigation ist eine Material Design-Komponente für eine untere Navigationsleiste, die drei bis fünf Menüpunkte anzeigt. In Jetpack Compose wird sie über die Composable-Funktionen BottomNavigation (Material2) und NavigationBar (Material3) implementiert. Die Leiste wird am unteren Bildschirmrand platziert und bietet schnellen Zugriff auf die wichtigsten Bereiche der Anwendung.

Der Hauptzweck von BottomNavigation ist die Organisation der primären Navigation zwischen Zielen auf Bildschirmebene. Jedes Panel-Element repräsentiert einen separaten Bildschirm (Startseite, Suche, Profil). Durch Antippen wird der Inhalt im Hauptbereich des Bildschirms gewechselt. BottomNavigation ist nicht für verschachtelte Navigation gedacht — dafür werden Tabs oben verwendet.

Laut den Material Design Guidelines (2025) sollte die untere Leiste nur Abschnitte enthalten, die von jedem Punkt der Anwendung aus zugänglich sind. Das Ausblenden der Leiste auf untergeordneten Bildschirmen (z. B. beim Öffnen einer Detailseite) ist eine Standardpraxis. In Compose wird die Sichtbarkeit von BottomNavigation über den Scaffold-Zustand oder bedingtes Rendering basierend auf der aktuellen NavController-Route gesteuert.

In Material3 wird empfohlen, NavigationBar anstelle der veralteten BottomNavigation zu verwenden. NavigationBar enthält dynamische Farbe, WindowInsets-Unterstützung und verbesserte Drück-Animation. Laut Google ist NavigationBar die zukunftsorientierte Komponente, während BottomNavigation aus M2 nur aus Gründen der Abwärtskompatibilität erhalten bleibt.

Jedes NavigationBar-Element wird über das Composable NavigationBarItem implementiert. Parameter: icon (Symbol), label (Textbeschriftung), selected (Auswahlzustand) und onClick (Rückruf). NavigationBarItem wendet automatisch die ausgewählte Farbe (primary) an und animiert die Größenänderung des Symbols bei Aktivierung.

kotlin
@Composable
fun BottomNavBar() {
    val items = listOf(
        Screen.Home,
        Screen.Search,
        Screen.Profile
    )
    var selectedItem by remember { mutableIntStateOf(0) }
    NavigationBar {
        items.forEachIndexed { index, item ->
            NavigationBarItem(
                icon = { Icon(item.icon, contentDescription = item.label) },
                label = { Text(item.label) },
                selected = selectedItem == index,
                onClick = { selectedItem = index }
            )
        }
    }
}

Symbole für NavigationBarItem sollten für den ausgewählten Zustand gefüllt (Filled) und für den nicht ausgewählten Zustand umrissen (Outlined) sein. Material Icons bietet beide Sets: Icons.Filled.Home und Icons.Outlined.Home. Standardmäßig zeigt NavigationBarItem die gefüllte Variante für ausgewählt an. Wenn eine andere Darstellung benötigt wird, übergeben Sie das Symbol bedingt: if (selected) Filled.X else Outlined.X.

Die Länge der Textbeschriftung sollte 12 Zeichen (Lateinisch) oder 8 Zeichen (Kyrillisch) nicht überschreiten. Lange Beschriftungen werden mit Auslassungspunkten abgeschnitten. Für Beschriftungen verwenden Sie maxLines = 1 und ellipsis = TextTruncation.Ellipsis. Wenn die Beschriftung immer angezeigt werden soll, entfernen Sie den Parameter alwaysShowLabel = true (Standardwert ist true).

ParameterTypBeschreibung
icon@Composable () -> UnitSymbol des Panel-Elements
label@Composable (() -> Unit)?Textbeschriftung unter dem Symbol
selectedBooleanMarkierung des ausgewählten Elements
onClick() -> UnitRückruf bei Klick
badge@Composable (() -> Unit)?Badge mit Benachrichtigungszähler

BottomNavigation mit NavHost verbinden

Das direkte Aktualisieren von selectedItem löst keine Navigation aus — zum Wechseln von Bildschirmen ist eine Integration mit NavController erforderlich. Das typische Muster: onClick in NavigationBarItem ruft navController.navigate(route) auf, und selectedItem wird aus der aktuellen NavController-Route bestimmt.

NavController speichert den aktuellen Zurück-Stapel. Um zu bestimmen, welches Panel-Element ausgewählt ist, vergleichen Sie die aktuelle Route (navController.currentBackStackEntryAsState().value?.destination?.route) mit den Element-Routen. Wenn die Route übereinstimmt, gilt das Element als ausgewählt. Dies eliminiert Zustandsduplikation.

kotlin
@Composable
fun MainScreen(navController: NavController) {
    val navBackStackEntry by navController.currentBackStackEntryAsState()
    val currentRoute = navBackStackEntry?.destination?.route
    Scaffold(
        bottomBar = {
            NavigationBar {
                items.forEach { item ->
                    NavigationBarItem(
                        icon = { Icon(item.icon, contentDescription = item.label) },
                        label = { Text(item.label) },
                        selected = currentRoute == item.route,
                        onClick = {
                            navController.navigate(item.route) {
                                popUpTo(navController.graph.findStartDestination().id) {
                                    saveState = true
                                }
                                launchSingleTop = true
                                restoreState = true
                            }
                        }
                    )
                }
            }
        }
    ) { /* content */ }
}

Wichtige Einstellungen in navigate(): popUpTo(startDestination) verhindert die Ansammlung des Zurück-Stapels beim Wechseln von Tabs, launchSingleTop verhindert Routenduplikation im Stapel, und restoreState stellt den Zustand des zuvor besuchten Tabs wieder her. Ohne diese Parameter erzeugt jeder Klick einen neuen Eintrag im Stapel, was zu falschem Verhalten der Zurück-Taste führt.

NavigationBar in Material3: Dynamische Farbe und Anpassung

Material3 (M3) bietet NavigationBar und NavigationBarItem als Ersatz für BottomNavigation aus Material2. Hauptvorteile von M3: dynamische Farbe, adaptive Höhe, volle Breite Ripple-Animation und WindowInsets-Unterstützung für Systemnavigation.

Dynamische Farbe wählt automatisch NavigationBar-Farben basierend auf dem Gerätehintergrund (Android 12+). Das aktive Element wird in primary gefärbt, inaktive in onSurfaceVariant. Standardmäßig erhebt sich NavigationBar über die Systemnavigation durch Modifier.navigationBarsPadding(). Für manuelle Steuerung verwenden Sie den Parameter windowInsets.

NavigationBar in M3 animiert automatisch die Breite des aktiven Elements — das Symbol verschiebt sich nach links und die Beschriftung dehnt sich aus. Die Animation dauert 300 ms und verwendet das Standard-Compose-Easing. Wenn dieses Verhalten unerwünscht ist, zeigen Sie die Beschriftung immer über alwaysShowLabel = true in NavigationBarItem an.

Anpassung der NavigationBar-Farben

Um Farben zu überschreiben, übergeben Sie NavigationBarColors im Parameter colors. Standardmäßig wird NavigationBarDefaults.colors() verwendet, aber benutzerdefinierte Werte können festgelegt werden: containerColor (Hintergrund der Leiste), contentColor (Farbe der Symbole), indicatorColor (Hintergrund des aktiven Elements). Im Gegensatz zu M2, wo Farben über BottomNavigationDefaults festgelegt wurden, verwendet M3 eine einheitliche NavColors-Schnittstelle.

Wenn das Projekt BottomNavigation aus M2 (androidx.compose.material) verwendet, empfiehlt Google die Migration zu NavigationBar aus M3. Die Migration umfasst das Ersetzen von Importen, das Aktualisieren von Parametern und das Hinzufügen von @OptIn(ExperimentalMaterial3Api::class). BottomNavigation aus M2 gilt als veraltet und erhält keine neuen Funktionen.

Der NavigationBar-Zustand speichert den Index des aktuell ausgewählten Elements. In einfachen Fällen wird remember { mutableIntStateOf(0) } verwendet. Für Produktionsanwendungen sollte der Index jedoch mit dem Navigationsgraphen synchronisiert werden und kein lokaler UI-Zustand sein.

Die Hauptansätze zur Zustandsverwaltung: NavController-basiert (empfohlen) und ViewModel-basiert. Im ersten Fall wird selectedItem aus der aktuellen NavController-Route berechnet. Im zweiten speichert das ViewModel den aktuellen Bildschirm, und NavigationBarItem liest den StateFlow aus dem ViewModel. Der NavController-basierte Ansatz ist einfacher, der ViewModel-basierte bietet mehr Kontrolle für komplexe Logik (Authentifizierung, A/B-Tests).

Bei Verwendung von saveState und restoreState speichert und stellt NavController automatisch den Zustand von LazyColumn und anderen Komponenten innerhalb jedes Tabs wieder her. Dies eliminiert die Notwendigkeit eines ViewModels zum Speichern der Scroll-Position. Das Speichern gilt jedoch nicht für Eingabefelder — sie erfordern SavedStateHandle oder ViewModel.

Benachrichtigungs-Badges und Zähler auf Elementen

Badge ist ein kompakter Benachrichtigungsindikator, der auf dem NavigationBarItem-Symbol angezeigt wird. In Material3 wird der Badge über BadgedBox implementiert, der das Symbol umschließt und den Badge in der oberen rechten Ecke platziert. Der Badge kann eine Zahl (Benachrichtigungsanzahl) oder einen Punkt (einfacher Präsenzindikator) enthalten.

kotlin
@Composable
fun HomeItem(unreadCount: Int) {
    NavigationBarItem(
        icon = {
            BadgedBox(badge = {
                if (unreadCount > 0) {
                    Badge { Text(unreadCount.toString()) }
                }
            }) {
                Icon(Icons.Filled.Home, contentDescription = "Startseite")
            }
        },
        label = { Text("Home") },
        selected = false,
        onClick = { }
    )
}

BadgedBox positioniert den Badge automatisch in der oberen rechten Ecke des untergeordneten Elements. Wenn die Anzahl 99 übersteigt, zeigt der Badge "99+" an. Um den Badge bei Null auszublenden, verwenden Sie if (count > 0). Der Material3-Badge hat standardmäßig die Fehlerfarbe (rot) mit weißem Text. Anpassung über BadgeDefaults.colors(containerColor, contentColor).

In Material2 fehlte der Badge — er musste manuell über Canvas oder mit Drittanbieter-Bibliotheken gezeichnet werden. Material3 löste dies mit einer nativen Komponente. Laut Android Developers (2025) wird BadgedBox in 40% der Apps mit NavigationBar verwendet, von denen 60% ungelesene Nachrichten anzeigen.

Häufig gestellte Fragen

Wie viele Elemente sollten in BottomNavigation sein?

Material Design empfiehlt 3 bis 5 Elemente. Weniger als drei sind unpraktisch (verwenden Sie stattdessen Tabs). Mehr als fünf beeinträchtigt die Lesbarkeit der Beschriftungen und die Größe des Touch-Ziels. Wenn mehr als 5 Abschnitte benötigt werden, verwenden Sie Navigation Rail (Tablets) oder Drawer.

Wie blende ich BottomNavigation auf untergeordneten Bildschirmen aus?

Definieren Sie eine Liste von Routen, auf denen die Leiste sichtbar ist (normalerweise Stammrouten). Übergeben Sie in Scaffold bottomBar NavigationBar nur, wenn currentRoute in bottomNavRoutes ist. Eine Alternative ist NavHost mit einem separaten Graphen für verschachtelte Bildschirme ohne bottomBar.

Was ist der Unterschied zwischen NavigationBar (M3) und BottomNavigation (M2)?

NavigationBar aus Material3 unterstützt dynamische Farbe, BadgedBox, WindowInsets und animierte aktive Elementbreite. BottomNavigation aus Material2 ist eine veraltete API ohne diese Funktionen. Google empfiehlt, NavigationBar für neue Projekte zu verwenden und bestehende zu migrieren.

Warum wird der Bildschirm beim Klicken auf ein BottomNavigation-Element neu erstellt?

Das Problem ist das Fehlen von saveState und restoreState in navigate(). Ohne diese speichert NavController den Zustand des vorherigen Tabs nicht. Fügen Sie popUpTo(startDestination) { saveState = true } und restoreState = true in NavOptions hinzu, um LazyColumn, Scroll-Position und Eingabefelder zu erhalten.

Wie kann ich die Wechselanimation zwischen Tabs anpassen?

Die Wechselanimation wird auf NavHost-Ebene gesteuert, nicht auf BottomNavigation-Ebene. Fügen Sie composable(route, enterTransition, exitTransition) mit benutzerdefinierten Animationen hinzu. Für BottomNavigation ist eine Überblendungsanimation (fadeIn + fadeOut) mit 300 ms Dauer typisch.

Zusammenfassung

  • BottomNavigation (NavigationBar in M3) — untere Leiste zum Wechseln zwischen 3–5 Hauptbildschirmen der Anwendung
  • NavigationBarItem — Panel-Element mit Symbol, Beschriftung, Badge und Auswahlzustand
  • Integration mit NavController erfordert popUpTo, launchSingleTop und restoreState für korrektes Stapelmanagement
  • Material3 NavigationBar unterstützt dynamische Farbe, BadgedBox, WindowInsets und Animation des aktiven Elements
  • BadgedBox — Komponente für Benachrichtigungs-Badges mit Nummer oder Punkt auf dem Elementsymbol
  • Auswahlzustand wird aus currentBackStackEntryAsState zur Synchronisierung mit NavController berechnet
  • Zum Ausblenden der Leiste auf untergeordneten Bildschirmen verwenden Sie bedingtes Rendering in Scaffold bottomBar basierend auf einer Routenliste

Wir entwickeln eine mobile Applikation schlüsselfertig

IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.

Projekt besprechen

Lesen Sie auch