Bottom Navigation Bar with Jetpack Compose

Gaurav
4 min readJun 12, 2021

--

Photo by Axel Antas-Bergkvist on Unsplash

Note: You need to have Android Studio Arctic Fox to use Jetpack Compose in your project.

Adding libraries

Open your project-level build.gradle file, and add the following extension:

buildscript {
ext {
compose_version = '1.0.0-beta08'
}
//....
}

Open your app-level build.gradle file, and add the following

android {
//..
buildFeatures {
compose true
}
composeOptions {
kotlinCompilerExtensionVersion compose_version
kotlinCompilerVersion '1.5.10'
}
}
dependencies {

implementation "androidx.compose.ui:ui:$compose_version"
implementation androidx.compose.material:material:$compose_version"
implementation "androidx.compose.ui:ui-tooling:$compose_version"
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.1'
implementation 'androidx.activity:activity-compose:1.3.0-beta01'
implementation "androidx.navigation:navigation-runtime-ktx:2.4.0- alpha02@aar"
implementation "androidx.navigation:navigation-compose:2.4.0-alpha02"

}

Now create the TopBar and Bottom Navigation Bar

TopBar

In your compose activity, add the following code outside the main class. We have used TopAppBar composable function and set the title, background color and content color.

@Composable
fun TopBar() {
TopAppBar(
title = { Text(text = stringResource(R.string.app_name), fontSize = 18.sp) },
backgroundColor = colorResource(id = R.color.teal_700),
contentColor = Color.White
)
}

Bottom Navigation Bar

To add Bottom Navigation Bar, we first need to think about the tabs in it. To show tabs, we will create a sealed class BottomNavigationItem with different options.

Create sealed class as follows.

sealed class BottomNavigationItem(var route: String, var icon: Int, var title: String) {
object One : BottomNavigationItem("one", android.R.drawable.ic_media_play, "One")
object Two : BottomNavigationItem("two", android.R.drawable.ic_media_play, "Two")
object Three : BottomNavigationItem("three", android.R.drawable.ic_media_play, "Three")
object Four : BottomNavigationItem("four", android.R.drawable.ic_media_play, "Four")
object Five : BottomNavigationItem("five", android.R.drawable.ic_media_play, "Five")
}

Next, similar to TopAppBar, add following code outside of your main class.

@Composable
fun BottomNavigationBar() {
val items = listOf(
BottomNavigationItem.One,
BottomNavigationItem.Two,
BottomNavigationItem.Three,
BottomNavigationItem.Four,
BottomNavigationItem.Five
)
BottomNavigation(
backgroundColor = colorResource(id = R.color.teal_700),
contentColor = Color.White
) {

items.forEach { item ->
BottomNavigationItem(
icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
label = { Text(text = item.title) },
selectedContentColor = Color.White,
unselectedContentColor = Color.White.copy(0.4f),
alwaysShowLabel = true,
selected = false,
onClick = {
//...

}
}
)
}
}
}

As we have created the composable functions for TopAppBar and BottomNaviagionBar. Now its time to put them together. Add following composable function outside the main class.

@Composable
fun MainScreen() {
Scaffold(
topBar = { TopBar() },
bottomBar = { BottomNavigationBar(navController) }
)
}

Now, its time to create screens for different tabs in BottomNavigationBar

To create the screens, create a file and add following composable functions in it. Here we have FirstScreen, SecondScreen, ThirdScreen, FourthScreen, FifthScreen composable functions.

@Composable
fun FirstScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.wrapContentSize(Alignment.Center)
) {
Text(
text = "First View",
fontWeight = FontWeight.Bold,
color = Color.Black,
modifier = Modifier.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center,
fontSize = 25.sp
)
}
}


@Composable
fun SecondScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.wrapContentSize(Alignment.Center)
) {
Text(
text = "Second View",
fontWeight = FontWeight.Bold,
color = Color.Black,
modifier = Modifier.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center,
fontSize = 25.sp
)
}
}

@Composable
fun ThirdScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.wrapContentSize(Alignment.Center)
) {
Text(
text = "Third View",
fontWeight = FontWeight.Bold,
color = Color.Black,
modifier = Modifier.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center,
fontSize = 25.sp
)
}
}

@Composable
fun FourthScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.wrapContentSize(Alignment.Center)
) {
Text(
text = "Fourth View",
fontWeight = FontWeight.Bold,
color = Color.Black,
modifier = Modifier.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center,
fontSize = 25.sp
)
}
}

@Composable
fun FifthScreen() {
Column(
modifier = Modifier
.fillMaxSize()
.background(Color.White)
.wrapContentSize(Alignment.Center)
) {
Text(
text = "Fifth View",
fontWeight = FontWeight.Bold,
color = Color.Black,
modifier = Modifier.align(Alignment.CenterHorizontally),
textAlign = TextAlign.Center,
fontSize = 25.sp
)
}
}

To attach above created screens with BottomNavigationBar, first create the following composable function Navigate. It takes two parameters, NavHostController and route(String). NavHost is a NavGraphBuilder.

@Composable
fun Navigation(navController: NavHostController, route: String) {
NavHost(navController = navController, startDestination = route) {
composable(BottomNavigationItem.One.route) {
FirstScreen()
}
composable(BottomNavigationItem.Two.route) {
SecondScreen()
}
composable(BottomNavigationItem.Three.route) {
ThirdScreen()
}
composable(BottomNavigationItem.Four.route) {
FourthScreen()
}
composable(BottomNavigationItem.Five.route) {
FifthScreen()
}

}
}

In the MainScreen(), we create the Navigation Controller, and we’re passing it to the BottomNavigationBar and Navigation created above.

@Composable
fun MainScreen() {
val navController = rememberNavController()
Scaffold(
topBar = { TopBar() },
bottomBar = { BottomNavigationBar(navController) }
) {
Navigation(navController = navController, BottomNavigationItem.One.route)

}
}

Next, in the BottomNavigationBar, add the parameter navController, and create the navBackStackEntry and the currentRoute.

Using the currentRoute, we check if we have to highlight the bar item or not, and we navigate to the view using the navigate() method

@Composable
fun BottomNavigationBar(navController: NavController) {
val items = listOf(
BottomNavigationItem.One,
BottomNavigationItem.Two,
BottomNavigationItem.Three,
BottomNavigationItem.Four,
BottomNavigationItem.Five
)
BottomNavigation(
backgroundColor = colorResource(id = R.color.teal_700),
contentColor = Color.White
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route

items.forEach { item ->
BottomNavigationItem(
icon = { Icon(painterResource(id = item.icon), contentDescription = item.title) },
label = { Text(text = item.title) },
selectedContentColor = Color.White,
unselectedContentColor = Color.White.copy(0.4f),
alwaysShowLabel = true,
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
// Pop up to the start destination of the graph to
// avoid building up a large stack of destinations
// on the back stack as users select items
navController.graph.startDestinationRoute?.let { route ->
popUpTo(route) {
saveState = true
}
}
// Avoid multiple copies of the same destination when
// reselecting the same item
launchSingleTop = true
// Restore state when reselecting a previously selected item
restoreState = true
}
}
)
}
}
}

Thats It. You are ready with BottomNaviagtionBar Integration with Compose and Jetpack Navigation.

Find Code on Github — https://github.com/radaurgaurav/BottomNavigationInCompose

--

--

Gaurav

Android App Developer, Yoga Practitioner, Running Enthusiast