BottomNavigation (NavigationBar i Material3) är en Material Design-komponent som ger navigering mellan tre till fem huvudskärmar i applikationen. I Jetpack Compose implementeras bottenpanelen via NavigationBar eller BottomNavigation, där varje element representeras av en ikon och en textetikett. Enligt Google Material Design (2025) rekommenderas BottomNavigation för iOS och Android som det primära navigeringsmönstret. Panelen anpassar sig automatiskt till höjden av systemnavigering (Gesture Navigation) via WindowInsets. NavigationBar i Material3 stödjer dynamic color, badge och adaptiva marginaler.
Huvudpunkter
BottomNavigation är en Material Design-komponent för bottennavigeringspanelen som visar tre till fem menyalternativ. I Jetpack Compose implementeras den via composable-funktionerna BottomNavigation (Material2) och NavigationBar (Material3). Panelen placeras längst ner på skärmen och ger snabb åtkomst till viktiga delar av applikationen.
Huvuduppgiften för BottomNavigation är att organisera primär navigering mellan skärmnivåer. Varje element i panelen representerar en separat skärm (Home, Search, Profile). Tryckning växlar innehållet i huvudområdet på skärmen. BottomNavigation är inte avsett för kapslad navigering — för detta används flikar (Tabs) längst upp.
Enligt Material Design Guidelines (2025) bör bottenpanelen endast innehålla de sektioner som är tillgängliga från vilken punkt som helst i applikationen. Att dölja panelen på underordnade skärmar (t.ex. när en detaljsida öppnas) är standardpraxis. I Compose hanteras synligheten av BottomNavigation via Scaffold-status eller villkorlig rendering baserat på den aktuella NavController-vägen.
I Material3 rekommenderas att använda NavigationBar istället för Legacy BottomNavigation. NavigationBar innehåller Dynamic Color, stöd för WindowInsets och förbättrad tryckanimation. Enligt Google är NavigationBar en framtidsinriktad komponent, medan BottomNavigation från M2 endast finns kvar för bakåtkompatibilitet.
Varje NavigationBar-element implementeras via composable NavigationBarItem. Elementets parametrar: icon (ikon), label (textetikett), selected (valstatus) och onClick (callback). NavigationBarItem tillämpar automatiskt den valda färgen (primary) och animationen av ikonstorleksändring vid aktivering.
@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 }
)
}
}
}
Ikoner för NavigationBarItem bör vara Filled för valt tillstånd och Outlined för icke-valt tillstånd. Material Icons tillhandahåller båda uppsättningarna: Icons.Filled.Home och Icons.Outlined.Home. Som standard visar NavigationBarItem filled-varianten för selected. Om olika visning behövs, skicka ikonen villkorligt: if (selected) Filled.X else Outlined.X.
Längden på elementets textetikett — högst 12 tecken (latinska alfabetet) eller 8 tecken (kyrilliska). Långa etiketter trunkeras med ellips. För etiketter, använd maxLines = 1 och ellipsis = TextTruncation.Ellipsis. Om etiketten alltid behövs, ställ in parametern alwaysShowLabel = true (standard true).
| Parameter | Typ | Beskrivning |
|---|---|---|
| icon | @Composable () -> Unit | Ikon för panelelement |
| label | @Composable (() -> Unit)? | Textetikett under ikonen |
| selected | Boolean | Flagga för valt element |
| onClick | () -> Unit | Callback vid tryckning |
| badge | @Composable (() -> Unit)? | Märke med antal aviseringar |
Direkt uppdatering av selectedItem omdirigerar inte navigeringen — för att växla skärmar krävs integrering med NavController. Det typiska mönstret: onClick i NavigationBarItem anropar navController.navigate(route), och selectedItem bestäms från den aktuella vägen för NavController.
NavController lagrar den aktuella back stacken. För att avgöra vilket panelelement som är valt, jämför den aktuella vägen (navController.currentBackStackEntryAsState().value?.destination?.route) med elementens vägar. Om vägen matchar — anses elementet vara valt. Detta eliminerar duplicering av status.
@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 */ }
}
Viktiga inställningar i navigate(): popUpTo(startDestination) förhindrar ansamling av back stack vid växling av flikar, launchSingleTop utesluter duplicering av vägen i stacken, och restoreState återställer status för tidigare besök på fliken. Utan dessa parametrar skapar varje tryckning en ny post i stacken, vilket leder till felaktigt beteende hos bakåtknappen.
Material3 (M3) erbjuder NavigationBar och NavigationBarItem som ersättning för BottomNavigation från Material2. Viktigaste fördelarna med M3: Dynamic Color, adaptiv höjd, ripple-animering över hela elementets bredd och stöd för WindowInsets för att ta hänsyn till systemnavigering.
Dynamic Color väljer automatiskt färger för NavigationBar baserat på enhetens bakgrund (Android 12+). Det aktiva elementet färgas i primary, inaktiva — i onSurfaceVariant. Som standard höjs NavigationBar över systemnavigeringen via Modifier.navigationBarsPadding(). För manuell kontroll, använd parametern windowInsets.
NavigationBar i M3 animerar automatiskt bredden på det aktiva elementet — ikonen flyttas åt vänster och etiketten expanderar. Animationen varar 300 ms och använder standard Compose-easing. Om detta beteende är oönskat, ställ in etiketten alltid synlig via alwaysShowLabel = true i NavigationBarItem.
För att åsidosätta färger, skicka NavigationBarColors i parametern colors. Som standard används NavigationBarDefaults.colors(), men du kan ställa in egna färger: containerColor (panelbakgrund), contentColor (ikonfärg), indicatorColor (aktivt elements bakgrund). Till skillnad från M2, där färger ställdes in via BottomNavigationDefaults, används i M3 det enhetliga gränssnittet NavColors.
Om BottomNavigation från M2 (androidx.compose.material) används i projektet, rekommenderar Google migrering till M3 NavigationBar. Migreringen omfattar byte av importer, uppdatering av parametrar och tillägg av @OptIn(ExperimentalMaterial3Api::class). BottomNavigation från M2 anses vara föråldrad och får inga nya funktioner.
Status för NavigationBar lagrar index för det aktuellt valda elementet. I enkla fall används remember { mutableIntStateOf(0) }. För produktionsapplikationer bör index dock synkroniseras med navigeringsgrafen, inte vara ett lokalt UI-tillstånd.
Huvudmetoder för status hantering: NavController-based (rekommenderas) och ViewModel-based. I det första fallet beräknas selectedItem från den aktuella vägen för NavController. I det andra fallet — ViewModel lagrar den aktuella skärmen och NavigationBarItem läser StateFlow från ViewModel. NavController-based är enklare, ViewModel-based ger mer kontroll vid komplex logik (autentisering, A/B-tester).
Vid användning av saveState och restoreState sparar och återställer NavController automatiskt status för LazyColumn och andra komponenter inom varje flik. Detta eliminerar behovet av ViewModel för att lagra scrollposition. Sparning gäller dock inte inmatningsfält — de kräver SavedStateHandle eller ViewModel.
Badge är en kompakt aviseringsindikator som visas på ikonen för NavigationBarItem. I Material3 implementeras märket via BadgedBox, som omsluter ikonen och placerar märket i det övre högra hörnet. Badge kan innehålla ett nummer (antal aviseringar) eller en punkt (enkel indikation på närvaro).
@Composable
fun HomeItem(unreadCount: Int) {
NavigationBarItem(
icon = {
BadgedBox(badge = {
if (unreadCount > 0) {
Badge { Text(unreadCount.toString()) }
}
}) {
Icon(Icons.Filled.Home, contentDescription = "Hem")
}
},
label = { Text("Home") },
selected = false,
onClick = { }
)
}
BadgedBox positionerar automatiskt Badge i det övre högra hörnet av det underordnade elementet. Om numret överstiger 99 visar Badge “99+”. För att dölja märket vid nollvärde, använd villkoret if (count > 0). Badge från Material3 har som standard färgen error (röd) med vit text. Anpassning via BadgeDefaults.colors(containerColor, contentColor).
I Material2 fanns märket inte — det måste ritas manuellt via Canvas eller använda tredjepartsbibliotek. Material3 löste detta problem med en inbyggd komponent. Enligt Android Developers (2025) används BadgedBox i 40% av applikationerna med NavigationBar, varav 60% för att visa olästa meddelanden.
Vanliga frågor
Material Design rekommenderar 3 till 5 element. Mindre än tre — inte ändamålsenligt (bättre att använda Tabs). Fler än fem — försämrar läsbarheten av etiketter och minskar touch-target. Om mer än 5 sektioner behövs, använd Navigation Rail (surfplattor) eller Drawer.
Bestäm listan över vägar där panelen är synlig (vanligtvis rotvägar). I Scaffold bottomBar, skicka NavigationBar endast om currentRoute finns i bottomNavRoutes. Alternativ — NavHost med separat graf för kapslade skärmar utan bottomBar.
NavigationBar från Material3 stödjer Dynamic Color, BadgedBox, WindowInsets och animerad bredd på aktivt element. BottomNavigation från Material2 är ett gammalt API utan dessa funktioner. Google rekommenderar att använda NavigationBar för nya projekt och migrera befintliga.
Problemet är avsaknaden av saveState och restoreState i navigate(). Utan dem sparar inte NavController status för föregående flik. Lägg till popUpTo(startDestination) { saveState = true } och restoreState = true i NavOptions för att bevara LazyColumn, scroll och inmatningsfält.
Växlingsanimationen styrs på nivån av NavHost, inte BottomNavigation. Lägg till composable(route, enterTransition, exitTransition) med anpassade animationer. För BottomNavigation är en fading-animation (fadeIn + fadeOut) med en varaktighet på 300ms typisk.
Sammanfattning
Vi utvecklar en mobil applikation nyckelfärdigt
IT Sectr skapar iOS- och Android-applikationer för startups och företag sedan 2017. Vi ger dig råd och föreslår den bästa lösningen.
Läs också