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.
Code
In the MainActivity
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
@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
enum class Screen {
Home,
Other
}
sealed class NavigationItem(val route: String) {
object Home : NavigationItem(Screen.Home.name)
object Other : NavigationItem(Screen.Other.name)
}
BottomNavigationBarItems
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.