I am posting a template that can be used to create a bottom navigation bar in Android Compose. The template is minimal with two icons that lead to two simple UI screens for the user. This will lead to less adjustment needed to alter to your use case.
I added some animations to the transitions. These can be removed or changed as well.
The bottom navigation is built into a Scaffold composable which is the main foundation for the application UI.
Code
In the MainActivity, create the Scaffold.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
SampleBottomNavigationTheme {
val navController = rememberNavController()
Scaffold(modifier = Modifier.fillMaxSize(),
bottomBar = {
CustomNavigationBar(navController)
}) { innerPadding ->
NavHost(
modifier = Modifier.fillMaxWidth().padding(innerPadding),
navController = navController,
startDestination = NavigationItem.Home.route,
enterTransition = { slideInHorizontally() + fadeIn() },
exitTransition = { slideOutHorizontally() + fadeOut() },
popEnterTransition = { slideInHorizontally() + fadeIn() },
popExitTransition = { slideOutHorizontally() + fadeOut() }
) {
composable(NavigationItem.Home.route) {
Home()
}
composable(NavigationItem.Other.route) {
Other()
}
}
}
}
}
}
}
@Composable
fun Home() {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(text = "Home")
}
}
@Composable
fun Other() {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(text = "Other")
}
}
To keep things organized, create a separate file for each of the following.
CustomNavigationBar is where the navigation is primarily built.
@Composable
fun CustomNavigationBar(
navController: NavController
) {
val navigationBarItems =
listOf(
BottomNavigationBarItems(
title = "Home",
selectedIcon = Icons.Default.Home,
unselectedIcon = Icons.Outlined.Home,
route = NavigationItem.Home.route
),
BottomNavigationBarItems(
title = "User",
selectedIcon = Icons.Sharp.AccountBox,
unselectedIcon = Icons.Outlined.AccountBox,
route = NavigationItem.Other.route
)
)
var bottomNavSelectedItemIndex by remember {
mutableIntStateOf(0)
}
navController.addOnDestinationChangedListener { controller, destination, arguments ->
navigationBarItems.forEachIndexed { index, bottomNavigationBarItems ->
if (bottomNavigationBarItems.route == destination.route)
bottomNavSelectedItemIndex = index
}
}
NavigationBar {
navigationBarItems.forEachIndexed { index, bottomNavigationBarItems ->
NavigationBarItem(
selected = if (bottomNavSelectedItemIndex == index) true else false,
onClick = {
bottomNavSelectedItemIndex = index
if (navController.currentDestination?.route != bottomNavigationBarItems.route) {
navController.navigate(
bottomNavigationBarItems.route
) {
launchSingleTop = true
}
}
},
icon = {
Icon(
imageVector = if (bottomNavSelectedItemIndex == index) bottomNavigationBarItems.selectedIcon else bottomNavigationBarItems.unselectedIcon,
contentDescription = bottomNavigationBarItems.title
)
})
}
}
}
NavigationItem holds a reference to all the navigation items.
enum class Screen {
Home,
Other
}
sealed class NavigationItem(val route: String) {
object Home : NavigationItem(Screen.Home.name)
object Other : NavigationItem(Screen.Other.name)
}
BottomNavigationBarItems is the data type for each navigation item. The route value is what is used in the bottom navigation bar to open the next UI screen.
data class BottomNavigationBarItems(
val title: String,
val selectedIcon: ImageVector,
val unselectedIcon: ImageVector,
val route : String
)
There you have it. Simple to adjust and make your own.
Hope this helps.