Jetpack Compose bottom navigation is a Material Design component that provides tab-based navigation at the bottom of your screen. Unlike traditional Android development where you'd use XML layouts and ViewPager, Jetpack Compose bottom navigation uses declarative programming principles to create responsive and interactive navigation experiences.
The core component for Jetpack Compose bottom navigation is BottomNavigation
, which works alongside BottomNavigationItem
composables to create individual navigation tabs. When implementing Jetpack Compose bottom navigation, you'll typically combine these components with Jetpack Navigation Compose library for full navigation functionality.
The BottomNavigation
composable serves as the container for your Jetpack Compose bottom navigation implementation. This component provides the foundation for organizing navigation items and handling user interactions.
BottomNavigation(
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White
) {
// Navigation items go here
}
The backgroundColor
property controls the background color of your Jetpack Compose bottom navigation bar, while contentColor
determines the default color for content within the navigation bar.
Each BottomNavigationItem
in your Jetpack Compose bottom navigation setup supports several key properties:
selected: A Boolean value indicating whether the current item is selected. This property is essential for Jetpack Compose bottom navigation state management.
BottomNavigationItem(
selected = currentRoute == "home",
onClick = { navController.navigate("home") }
)
onClick: A lambda function that executes when users tap the navigation item. In Jetpack Compose bottom navigation, this typically involves navigation actions.
icon: The composable that displays the navigation item's icon. Most Jetpack Compose bottom navigation implementations use Material Icons.
icon = {
Icon(
imageVector = Icons.Default.Home,
contentDescription = "Home"
)
}
label: An optional text label that appears below the icon in your Jetpack Compose bottom navigation.
label = {
Text("Home")
}
enabled: Controls whether the navigation item responds to user interactions in your Jetpack Compose bottom navigation.
alwaysShowLabel: Determines whether labels remain visible even when items aren't selected in Jetpack Compose bottom navigation.
selectedContentColor and unselectedContentColor: These properties control the visual appearance of selected and unselected items in Jetpack Compose bottom navigation.
Jetpack Compose bottom navigation works seamlessly with NavController for handling navigation logic. The NavController manages the navigation stack and coordinates with your Jetpack Compose bottom navigation implementation.
val navController = rememberNavController()
You'll use navController.navigate()
within your Jetpack Compose bottom navigation onClick handlers to navigate between destinations. The currentBackStackEntryAsState()
function helps track the current destination for Jetpack Compose bottom navigation state management.
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
For organized Jetpack Compose bottom navigation implementations, create a data class representing navigation items:
data class NavigationItem(
val title: String,
val icon: ImageVector,
val route: String
)
This approach makes your Jetpack Compose bottom navigation code more maintainable and allows easy modification of navigation items.
Jetpack Compose bottom navigation requires proper state management to highlight the currently selected item. You'll observe the NavController's back stack to determine which navigation item should appear selected.
The currentBackStackEntryAsState()
function provides a Compose State that updates whenever navigation occurs in your Jetpack Compose bottom navigation setup. This ensures your navigation bar reflects the current screen accurately.
Jetpack Compose bottom navigation offers extensive customization options. You can modify colors, typography, and spacing to match your app's design requirements.
Material Theme integration allows your Jetpack Compose bottom navigation to automatically adapt to your app's color scheme. However, you can override default colors using the backgroundColor
, contentColor
, selectedContentColor
, and unselectedContentColor
properties.
Your Jetpack Compose bottom navigation setup requires integration with NavHost
to define navigation destinations:
NavHost(
navController = navController,
startDestination = "home"
) {
composable("home") { HomeScreen() }
composable("profile") { ProfileScreen() }
composable("settings") { SettingsScreen() }
}
This integration ensures that Jetpack Compose bottom navigation actions trigger appropriate screen transitions.
Here's a comprehensive example demonstrating Jetpack Compose bottom navigation implementation with all necessary components:
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.NavHostController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.currentBackStackEntryAsState
import androidx.navigation.compose.rememberNavController
// Data class for navigation items
data class NavigationItem(
val title: String,
val icon: ImageVector,
val route: String
)
// Main composable with Jetpack Compose bottom navigation
@Composable
fun MainScreenWithBottomNavigation() {
val navController = rememberNavController()
// Define navigation items for Jetpack Compose bottom navigation
val navigationItems = listOf(
NavigationItem("Home", Icons.Default.Home, "home"),
NavigationItem("Search", Icons.Default.Search, "search"),
NavigationItem("Favorites", Icons.Default.Favorite, "favorites"),
NavigationItem("Profile", Icons.Default.Person, "profile")
)
Scaffold(
bottomBar = {
JetpackComposeBottomNavigation(
navController = navController,
navigationItems = navigationItems
)
}
) { paddingValues ->
NavHost(
navController = navController,
startDestination = "home",
modifier = Modifier.padding(paddingValues)
) {
composable("home") {
ScreenContent(
title = "Home Screen",
description = "Welcome to Jetpack Compose bottom navigation demo!"
)
}
composable("search") {
ScreenContent(
title = "Search Screen",
description = "Search functionality with Jetpack Compose bottom navigation"
)
}
composable("favorites") {
ScreenContent(
title = "Favorites Screen",
description = "Your favorite items using Jetpack Compose bottom navigation"
)
}
composable("profile") {
ScreenContent(
title = "Profile Screen",
description = "User profile with Jetpack Compose bottom navigation"
)
}
}
}
}
// Jetpack Compose bottom navigation implementation
@Composable
fun JetpackComposeBottomNavigation(
navController: NavController,
navigationItems: List<NavigationItem>
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
BottomNavigation(
backgroundColor = MaterialTheme.colors.primary,
contentColor = Color.White,
elevation = 8.dp
) {
navigationItems.forEach { item ->
BottomNavigationItem(
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
// Pop up to start destination to avoid building up back stack
popUpTo(navController.graph.startDestinationId) {
saveState = true
}
// Avoid multiple copies of same destination
launchSingleTop = true
// Restore state when reselecting previously selected item
restoreState = true
}
},
icon = {
Icon(
imageVector = item.icon,
contentDescription = item.title,
modifier = Modifier.size(24.dp)
)
},
label = {
Text(
text = item.title,
fontSize = 12.sp,
maxLines = 1
)
},
selectedContentColor = Color.White,
unselectedContentColor = Color.White.copy(alpha = 0.6f),
alwaysShowLabel = true
)
}
}
}
// Screen content composable for demonstration
@Composable
fun ScreenContent(
title: String,
description: String
) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = title,
fontSize = 24.sp,
fontWeight = FontWeight.Bold,
textAlign = TextAlign.Center
)
Spacer(modifier = Modifier.height(16.dp))
Text(
text = description,
fontSize = 16.sp,
textAlign = TextAlign.Center,
color = MaterialTheme.colors.onSurface.copy(alpha = 0.7f)
)
}
}
// Usage in your Activity or main composable
@Composable
fun MyApp() {
MaterialTheme {
MainScreenWithBottomNavigation()
}
}
To use this Jetpack Compose bottom navigation example in your Android project, add these dependencies to your build.gradle.kts
(Module: app):
dependencies {
implementation "androidx.compose.ui:ui:1.5.4"
implementation "androidx.compose.ui:ui-tooling-preview:1.5.4"
implementation "androidx.compose.material:material:1.5.4"
implementation "androidx.activity:activity-compose:1.8.1"
implementation "androidx.navigation:navigation-compose:2.7.5"
implementation "androidx.compose.material:material-icons-extended:1.5.4"
}
This complete Jetpack Compose bottom navigation implementation demonstrates how to create a fully functional navigation system with proper state management, smooth transitions, and Material Design compliance. The example shows how Jetpack Compose bottom navigation integrates with modern Android architecture patterns while providing an intuitive user experience.
Your Jetpack Compose bottom navigation setup will now handle navigation between different screens while maintaining proper visual feedback for the currently selected tab. The implementation follows Android development best practices and ensures your Jetpack Compose bottom navigation remains responsive and accessible across different device configurations.