How to Add Navigation Drawer in Jetpack Compose?
Step-by-step guides to add navigation drawer in Jetpack Compose for beginners
This is part of the Jetpack Compose navigation series:
Part 4 - How to Add Navigation Drawer in Jetpack Compose?
This tutorial is built on top of this existing bottom navigation demo app in part 1 that I created previously.
The app starts with login screen, then navigates to home screen. From home screen, you can navigate to either profile or search screen.
We're going to add the navigation drawer starting from the home screen.
1. Add Top App Bar with Navigation Icon Menu
The top app bar looks like this in home screen.
Implement
TopBar()
ComposableReturn if current route is login path, we only want to start showing the top app bar staring from home screen
@Composable
fun TopBar(
navController: NavController,
onNavigationIconClick: () -> Unit,
) {
val navBackStackEntry by navController.currentBackStackEntryAsState()
val currentRoute = navBackStackEntry?.destination?.route
if (currentRoute == null || currentRoute == NavRoute.Login.path) {
return
}
TopAppBar(
title = {
Text(text = stringResource(id = R.string.app_name))
},
navigationIcon = {
IconButton(onClick = onNavigationIconClick) {
Icon(
imageVector = Icons.Default.Menu,
contentDescription = null,
)
}
},
)
}
In
MainScreen()
, pass in theTopBar()
as parameter intoScaffold()
Remember also pass in the
scaffoldState
. If you miss this step, the navigation drawer won't be shownWhen the navigation icon is clicked, start the coroutine to call
scaffoldState.drawerState.open()
to open the navigation drawer (to be implemented later)
val navController = rememberNavController()
val scaffoldState = rememberScaffoldState()
val scope = rememberCoroutineScope()
Scaffold(
scaffoldState = scaffoldState,
topBar = { TopBar(
navController =navController,
onNavigationIconClick = {
scope.launch {
scaffoldState.drawerState.open()
}
}
) },
bottomBar = { BottomBarNav(navController = navController) },
) {
NavGraph(navController)
}
2. Add Navigation Drawer and Body
The preview looks like this.
- Add drawer header, the header is just a simple text
@Composable
fun DrawerHeader(){
Row(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 64.dp)
,
horizontalArrangement = Arrangement.Center,
) {
Text(text = "Header", fontSize = 60.sp)
}
}
- Add drawer menu item which contains icon and text in a row
@Composable
private fun DrawerMenuItem(
iconDrawableId: Int,
text: String,
onItemClick: () -> Unit){
Row(
modifier = Modifier
.fillMaxWidth()
.clickable {onItemClick()}
.padding(16.dp),
verticalAlignment = Alignment.CenterVertically,
){
Icon(
painter = painterResource(iconDrawableId),
contentDescription = null,
)
Spacer(modifier = Modifier.width(16.dp))
Text(text = text, )
}
}
- Add drawer body to include the home and search drawer menu item
@Composable
fun DrawerBody(navController: NavHostController?, closeNavDrawer: () -> Unit) {
Column {
DrawerMenuItem(
iconDrawableId = R.drawable.ic_home,
text = NavRoute.Home.path,
onItemClick = {
navController?.navigate(NavRoute.Home.path)
closeNavDrawer()
}
)
DrawerMenuItem(
iconDrawableId = R.drawable.ic_search,
text = NavRoute.Search.path,
onItemClick = {
navController?.navigate(NavRoute.Search.withArgs("liang moi"))
closeNavDrawer()
}
)
}
}
Done
Source Code
GitHub Repository: Demo_SimpleNavigationCompose(bottom_nav_drawer branch)