In this demo, you’ll add bottom-bar navigation to the movie-booking app you’ve been building on in the previous lessons.
The Compose Material 3 dependency has already been set up in the project for convenience.
Open the starter project and go to MainActivity, where you see a newly added Scaffold composable that wraps the NavHost. Currently, it defines an empty lambda composable block as its bottomBar parameter. You must define the NavigationBar in this block.
In this demo, two destinations will be added in the bottom navigation:
— Home: Navigates to the app’s welcome screen. — Book Movie: Navigates to the movie-selection screen to initiate a booking.
Start by defining the NavigationBar composable:
bottomBar = {
NavigationBar {
}
}
Before adding the two NavigationBarItem composables, define a state variable that will represent the index of the selected NavigationBarItem.
var selectedNavBarIndex by remember { mutableIntStateOf(0) }
Scaffold(...) {
...
}
Note that the default value of 0 means that the item at index 0 — the welcome screen — will be pre-selected.
Here’s how you define the two NavigationBarItem composables:
NavigationBar {
NavigationBarItem(
selected = selectedNavBarIndex == 0,
label = { Text(text = "Home") },
onClick = {
navController.navigate(WELCOME_SCREEN.route)
},
icon = {
Icon(
imageVector = if (selectedNavBarIndex == 0) Icons.Filled.Home else Icons.Outlined.Home,
contentDescription = "Home"
)
}
)
NavigationBarItem(
selected = selectedNavBarIndex == 1,
label = { Text(text = "Book Movie") },
onClick = {
navController.navigate(MOVIE_SELECTION_SCREEN.route)
},
icon = {
Icon(
imageVector = if (selectedNavBarIndex == 1) Icons.Filled.Add else Icons.Outlined.Add,
contentDescription = "Book"
)
}
)
}
It’s important to note how the parameter selected in NavigationBarItem is evaluated and that the composable is rendered again if the value of selectedNavBarIndex changes. Also, in this case, you use a pair of icons to distinguish whether an item is selected or not.
However, you have not updated the value of selectedNavBarIndex yet when a NavigationBarItem is selected. Although a straightforward approach would be to update the value in the onClick, that would lead to an inconsistent UI state when the user navigates from the welcome screen to the movie-selection screen by clicking the ‘START’ button on the welcome screen. In this case, the NavigationBarItem selected state wouldn’t be updated.
Therefore, it would be ideal to update the selectedNavBarIndex when the destination in the navigation graph gets called. Here’s how the updated code would appear:
composable(WELCOME_SCREEN.route) {
selectedNavBarIndex = 0
WelcomeScreen(...)
}
composable(
MOVIE_SELECTION_SCREEN.route,
...
) { backStackEntry ->
selectedNavBarIndex = 1
MovieSelectionScreen(...)
}
Run the app and see the bottom navigation with the two navigation destinations — ‘Home’ and ‘Book Movie’. Try switching the destinations both via the bottom navigation and by clicking the ‘START’ button on the welcome screen, and observe that the correct NavigationBarItem gets highlighted based on the selection state.