Mastering Navigation in Android Compose UI — Integrating Bottom Navigation and Non-Bottom Menu Screens
Problem statement :-
I have been learning compose since last few months, and in one of the recent projects there was a UI design with the above mentioned flow (i.e) with and without bottom menus. And I wanted to implement it with Single Navigation Graph as the app has so minimal features and there is no specific requirement to use nested graph. (personally I thought…). So Let’s dive into the detailed steps you’ll need to follow in case you need to implement something like this.
Project setup :-
First create an empty Compose project in Android Studio. And then in the build.gradle file add the below dependencies inside the dependencies block
implementation("androidx.compose.material:material:1.6.7")
implementation("androidx.navigation:navigation-compose:2.7.7")
Creating the screens :-
Create a Kotlin file named as AppScreens.kt , In this file let’s create a sealed class to declare the Screens.
sealed class AppScreens(
val route: String,
val label: String,
val drawable: ImageVector? = null
) {
//direct screens
data object Splash : AppScreens(route = "splash", label = "SplashScreen")
data object Notifications : AppScreens(route = "notifications", label = "Notifications")
data object HomeToNextScreen : AppScreens(route = "homeToNext", label = "HomeToNextScreen")
//bottom menu screens
data object Home : AppScreens(
route = "home",
label = "Home",
drawable = Icons.Default.Home
)
data object Orders : AppScreens(
route = "orders",
label = "Orders",
drawable = Icons.Default.List
)
data object Profile : AppScreens(
route = "profile",
label = "Profile",
drawable = Icons.Default.AccountCircle
)
}
val bottomMenuScreens = listOf(
AppScreens.Home.route,
AppScreens.Profile.route,
AppScreens.Orders.route
)
In the above code, I have declared the screens that we will be using.
Creating Navigation Graph:
Lets create a navigation graph, Before that I wanted to say that the bottom menu is a part of Activity always if we need to make a single navigation and also I found that this approach works well, If you have any other ideas let me know in the comments.
@Composable
fun BuildAppNavGraph() {
val navController = rememberNavController()
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
val canShowBottomBar = currentRoute in bottomMenuScreens
Scaffold(
bottomBar = {
if (canShowBottomBar) {
BuildBottomNavigationBar(navController, currentRoute)
}
},
content = { paddingValues ->
Box(
modifier = Modifier.padding(
bottom = paddingValues.calculateBottomPadding()
)
) {
NavHost(
navController = navController,
startDestination = AppScreens.Splash.route
) {
composable(route = AppScreens.Splash.route) {
SplashScreen(navController)
}
composable(route = AppScreens.Home.route) {
HomeScreen(navController)
}
composable(route = AppScreens.Orders.route) {
OrdersScreen(navController)
}
composable(route = AppScreens.Profile.route) {
ProfileScreen(navController)
}
composable(route = AppScreens.Notifications.route) {
NotificationScreen(navController)
}
composable(route = AppScreens.HomeToNextScreen.route) {
HomeToNextScreen(navController)
}
}
}
}
)
}
This navigation graph, will be directly fed to the content of the activity as below.
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
Compose_single_graph_navigationTheme {
BuildAppNavGraph()
}
}
}
}
Now let’s construct the bottom menu, I have created a composable for that and that looks like below.,
@Composable
fun BuildBottomNavigationBar(
navController: NavHostController,
currentRoute: String?
) {
val bottomMenus = listOf(
AppScreens.Home,
AppScreens.Orders,
AppScreens.Profile
)
BottomAppBar(
modifier = Modifier.fillMaxWidth(),
content = {
bottomMenus.forEach { item ->
BottomNavigationItem(
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.startDestinationId)
launchSingleTop = true
}
},
icon = { Icon(imageVector = item.drawable!!, contentDescription = item.label) },
label = { Text(item.label) },
selectedContentColor = Color.Black,
unselectedContentColor = Color.Gray,
)
}
}
)
}
FYI, I’m including the git repo here so that you can see the code, Git link:
GitHub — itsgeniuS/compose_single_graph_navigation: Compose Android App with bottom menu and other…
Navigation implementation :
- Direct Navigation to screen : For the screens without bottom menu we can directly call like below,
Button(
onClick = {
navController.navigate(AppScreens.Home.route)
},
modifier = Modifier.padding(top = 10.dp)
) {
Text(text = "Open home")
}
2. Bottom Navigation item to screen : For the bottom menus, we will pop the previous screens and we will launch the new screen inside the same container as below,
BottomNavigationItem(
selected = currentRoute == item.route,
onClick = {
navController.navigate(item.route) {
popUpTo(navController.graph.startDestinationId)
launchSingleTop = true
}
},
icon = { Icon(imageVector = item.drawable!!, contentDescription = item.label) },
label = { Text(item.label) },
selectedContentColor = Color.Black,
unselectedContentColor = Color.Gray,
)
Conclusion:
Implementing single navigation graph with this approach has been never easy as far as I felt. By following this guide, you should be well-equipped to add a Bottom Navigation Bar to your next Jetpack Compose project.
Happy Coding ✌️ I Hope this helps you in any part of the work, Thanks guys. See you later…