Search code examples
androidandroid-jetpack-composeandroid-jetpack-navigationandroid-jetpack-compose-scaffold

How to create a drawer without TopAppBar in Jetpack Compose - Android


So i am new to Jetpack compose and am trying to figure out how to add the drawer functionality to a button on my view.

A counterpart question that i found for my question in relation to the XML imperative approach Navigation Drawer without Actionbar

Would love to learn about the approach to the same.


Solution

  • You can accomplish this in many ways i guess. I will only post 2 alternatives

    1- You can use Scaffold with drawerContent and adding your layout as this content

    val scaffoldState = rememberScaffoldState()
    
    val coroutineScope = rememberCoroutineScope()
    val openDrawer: () -> Unit = { coroutineScope.launch { scaffoldState.drawerState.open() } }
    val closeDrawer: () -> Unit = { coroutineScope.launch { scaffoldState.drawerState.close() } }
    
    
    Scaffold(
        scaffoldState = scaffoldState,
        drawerContent = {
            AppDrawer(
                currentRoute = currentRoute,
                navigateToHome = {
                    currentRoute = Routes.HOME_ROUTE
                    navController.popBackStack()
                    navController.navigate(currentRoute)
                },
                navigateToSettings = {
                    currentRoute = Routes.SETTINGS_ROUTE
                    navController.popBackStack()
                    navController.navigate(currentRoute)
                },
                closeDrawer = closeDrawer
            )
        },
    
    ) {
        NavHost(
            navController = navController,
            startDestination = Routes.HOME_ROUTE
        ) {
            composable(Routes.HOME_ROUTE) {
                HomeComponent()
            }
    
            composable(Routes.SETTINGS_ROUTE) {
                SettingsComponent()
            }
        }
    }
    

    Our drawer content

    @Composable
    fun AppDrawer(
        currentRoute: String,
        navigateToHome: () -> Unit,
        navigateToSettings: () -> Unit,
        closeDrawer: () -> Unit
    ) {
    
        Column(modifier = Modifier.fillMaxSize()) {
            DrawerHeader()
            DrawerButton(
                icon = Icons.Filled.Home,
                label = "Home",
                isSelected = currentRoute == Routes.HOME_ROUTE,
                action = {
                    if (currentRoute != Routes.HOME_ROUTE) {
                        navigateToHome()
                    }
                    closeDrawer()
                }
            )
    
            DrawerButton(
                icon = Icons.Filled.Settings,
                label = "Settings",
                isSelected = currentRoute == Routes.SETTINGS_ROUTE,
                action = {
                    if (currentRoute != Routes.SETTINGS_ROUTE) {
                        navigateToSettings()
                    }
                    closeDrawer()
                }
            )
        }
    }
    

    You need to set scaffoldState to have drawer to be able to open or close with other interactions other than drawable behavior. openDrawer and closeDrawer lambdas are required if you need to open or close drawer like touching an item on drawer on content.

    2- Using ModalDrawer

    @Composable
    private fun ModalDrawerComponent() {
        val drawerState = rememberDrawerState(DrawerValue.Closed)
        val coroutineScope = rememberCoroutineScope()
        val openDrawer: () -> Unit = { coroutineScope.launch { drawerState.open() } }
        val closeDrawer: () -> Unit = { coroutineScope.launch { drawerState.close() } }
        var selectedIndex by remember { mutableStateOf(0) }
    
        ModalDrawer(
            drawerState = drawerState,
            drawerContent = {
                ModalDrawerContentHeader()
                Divider()
                ModelDrawerContentBody(
                    selectedIndex,
                    onSelected = {
                        selectedIndex = it
                    },
                    closeDrawer = closeDrawer
                )
            },
            content = {
                Column(modifier = Modifier.fillMaxSize()) {
    //                ModalDrawerTopAppBar(openDrawer)
                    ModalContent(openDrawer)
                }
            }
        )
    }
    

    With ModalDrawer you set your Content as you wish if you don't want to add TopAppBar you just don't add it inside content. I commented it here to display that it's not there.

    You can check repo that contains implementations here.