Navigation Drawer with Material 3 in Jetpack Compose

Introduction

The navigation drawer is an important component of Android apps. It is utilized in many well-known Applications such as Gmail, LinkedIn, and many others. The Material 3 navigation drawer improved the user's experience. This post will go over all there is to know about the Navigation Drawer with Material. So let's get started.

Navigation Drawer with Material

According to the Material 3 design system, the primary navigation components are the Navigation Bar, Navigation Drawer, Navigation Rail, search, tabs, and the Top App Bar.

I previously explained the navigation bar in the previous article, which you may read here. Although there are numerous approaches to designing and implementing the navigation drawer in Android, we will begin with the most fundamental. The ultimate result will look like Below.

Navigation Drawer Example

 

Implementing the Navigation Drawer

Let's dive into how you can implement a navigation drawer using Material 3 in Jetpack Compose.

1. Add Dependency

Create a new project or open any project, then the following dependencies to your module build.gradle(App) file. These dependencies are already included in your project if you are using the most recent version of Android Studio.

implementation("androidx.compose.material3:material3")

2. Setting up The Navigation Drawer

In material 3, there are two sorts of navigation drawers: standard and model. The primary distinction between Material 2 and Material 3 navigation drawer is that Material 2 has square corners, but Material 3 has rounded corners, and Material 2 has shape whilst Material 3 has an updated style for displaying active destinations.

To create the navigation drawer, firstly, we must describe the content of the navigation drawer, for which we will define three Drawer items (Drawer item is a custom class that we have already defined), and to preserve the state in recomposition, we will utilize the navigation state, coroutine scope, and the selected index position. 

@Composable
fun MyApp() {

    val navigationState = rememberDrawerState(initialValue = DrawerValue.Closed)
    val scope = rememberCoroutineScope()
    var selectedItemIndex by rememberSaveable {
        mutableStateOf(0)
    }

    val items = listOf(
        DrawerItem(
            title = "Home",
            selectedIcon = Icons.Filled.Home,
            unselectedIcon = Icons.Outlined.Home,
        ),
        DrawerItem(
            title = "Notification",
            selectedIcon = Icons.Filled.Info,
            unselectedIcon = Icons.Outlined.Info,
            badgeCount = 45
        ),
        DrawerItem(
            title = "Favorites",
            selectedIcon = Icons.Filled.Favorite,
            unselectedIcon = Icons.Outlined.FavoriteBorder,
        ),
    )

    // to define navigation drawer here
}

data class DrawerItem(
    val title: String,
    val selectedIcon: ImageVector,
    val unselectedIcon: ImageVector,
    val badgeCount: Int? = null
)

3. Define the ModalNavigationDrawer

The ModalNavigationDrawer has drawer state and drawer content. Drawer Content is the area of the Navigation Drawer, while drawer state is the drawer's state. In the drawer Content, we will define a modelDrawerSheet(), but you can define any composable here. We have an image and three NavigationDrawerItems in the ModalDrawerSheet, each with text, an icon, and a chosen state. I've defined a DrawerFooter() composable here to show at the bottom. 

    Surface {
        ModalNavigationDrawer(
            drawerContent = {
                ModalDrawerSheet {
                    Spacer(modifier = Modifier.height(26.dp))
                    Image(
                        painter = painterResource(id = R.drawable.rv),
                        contentDescription = "",
                        modifier = Modifier
                            .size(150.dp)
                            .fillMaxWidth()
                            .align(CenterHorizontally)
                    )
                    Spacer(modifier = Modifier.height(26.dp))
                    items.forEachIndexed { index, drawerItem ->
                        NavigationDrawerItem(label = {
                            Text(text = drawerItem.title)
                        }, selected = index == selectedItemIndex, onClick = {
                            selectedItemIndex = index
                            scope.launch {
                                navigationState.close()
                            }
                        }, icon = {
                            Icon(
                                imageVector = if (index == selectedItemIndex) {
                                    drawerItem.selectedIcon
                                } else drawerItem.unselectedIcon,
                                contentDescription = drawerItem.title
                            )
                        }, badge = {
                            drawerItem.badgeCount?.let {
                                Text(text = drawerItem.badgeCount.toString())
                            }
                        }, modifier = Modifier.padding(NavigationDrawerItemDefaults.ItemPadding)
                        )

                    }
                    DrawerFooter()
                }
            },
            drawerState = navigationState,
        ) {
            Scaffold(topBar = {
                TopAppBar(title = {
                    Text(text = "My App")
                }, navigationIcon = {
                    IconButton(onClick = {
                        scope.launch {
                            navigationState.open()
                        }
                    }) {
                        Icon(imageVector = Icons.Default.Menu, contentDescription = "Menu")
                    }
                })
            }) {
                Column {
                    Text(
                        text = "Hii Learner",
                        modifier = Modifier
                            .padding(it)
                            .fillMaxSize(),
                        textAlign = TextAlign.Center
                    )
                }

            }

        }
    }

3. Define the DrawerFooter

Next, let's move on to crafting the Footer section of our Navigation Drawer. In this step, we wrap the Composable within a Column layout. Inside this layout, we incorporate a text element for the heading, followed by three icons placed within the item function of a Lazy Row. This layout choice ensures a streamlined arrangement of icons. If desired, you can seamlessly integrate hyperlinks to direct users to your various social media URLs.

@ExperimentalAnimationApi
@ExperimentalComposeUiApi
@Composable
fun DrawerFooter(
) {
    val uriHandler = LocalUriHandler.current

    Column(
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.Bottom,
        modifier = Modifier
            .fillMaxSize()
            .padding(bottom = 10.dp)
    ) {


        Spacer(modifier = Modifier.height(48.dp))
        Text(
            text = "Contact Creator",
            fontStyle = FontStyle.Italic,
            fontWeight = FontWeight.SemiBold,
        )

        LazyRow {
            item {
                IconButton(onClick = { }) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_linkedin),
                        modifier = Modifier.size(18.dp),
                        contentDescription = "Linkedin"
                    )
                }
                Spacer(modifier = Modifier.size(12.dp))

                IconButton(onClick = { }) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_github),
                        modifier = Modifier.size(18.dp),
                        contentDescription = "Github"
                    )
                }

                Spacer(modifier = Modifier.size(12.dp))

                IconButton(onClick = { }) {
                    Icon(
                        painter = painterResource(id = R.drawable.ic_twitter),
                        modifier = Modifier.size(18.dp),
                        contentDescription = "Twitter"
                    )
                }
            }
        }
    }
}

Output

navigation drawer example

Summary

In this article, we see how simple it is to incorporate a Navigation drawer into a Jetpack composition. Material 3 has made modern app design more accessible, intuitive, and adaptable than ever before. Feel free to leave comments with any suggestions or corrections for this article. Thank you!


Similar Articles