5

Recently I've been trying Material3 combined with Jetpack Compose, and I need a drawer along with a scaffold in one of my screen. It's sad that Scaffold in material3 hasn't support drawer yet, but luckily ModalNavigationDrawer can be found as a substitute. However, using ModalNavigationDrawer, the drawer's content is always covering the whole screen when drawer is opened, and I can't find any parameter to set it's width to a proper value, e.g. half of the screen width. Is there any way I can solve this problem? My compose version is 1.2.0-beta02 and my material3 version is 1.0.0-alpha12.

Gabriele Mariotti
  • 320,139
  • 94
  • 887
  • 841
Eynnzerr
  • 191
  • 2
  • 13
  • https://stackoverflow.com/questions/65305734/how-to-set-the-scaffold-drawer-width-in-jetpackcompose solution with Outline – vitidev Jul 07 '22 at 08:21

5 Answers5

4

Use a ModalDrawerSheet in the drawerContent and then set its modifier to the desired width:

ModalNavigationDrawer(
   drawerState = drawerState,
   drawerContent = {
      ModalDrawerSheet(
         modifier = Modifier
             .width(300.dp)    // or your desired width
             .fillMaxHeight()
      ) {

         ...Your Drawer Content...

      }
   }
) 

Code sample on the Material3 developer's page and the ModalDrawerSheet docs

Jim
  • 586
  • 4
  • 10
1

From the source code of ModalNavigationDrawer, the max-width is set in modifier and the drawer content's column is set to fill max size so by default it will take NavigationDrawerTokens.ContainerWidth's value as width.

But a work-around exists here, what you can do is you need to set drawerContainerColor as Color.Transparent and put another column or box inside the drawerContent with your required size.

You can use requiredWidth modifier to fix the required width or you can use sizeIn modifier according to min and max-width.

ModalNavigationDrawer(
        drawerContent = {
            Column(
                modifier = Modifier
                    .requiredWidth(250.dp)
                    .fillMaxHeight()
                    .background(Color.White, RoundedCornerShape(topEnd = 16.dp, bottomEnd = 16.dp))
            ) {
                //Drawer Content
            }
        },
        drawerContainerColor = Color.Transparent
    ) {
        //Main Content
    }

Update with click to close the drawer on tap of the background -

If you want to have the ripple effect on Spacer's clickable just remove the interactionSource and indication parameters.

val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
val scope = rememberCoroutineScope()

ModalNavigationDrawer(
   drawerState = drawerState,
   drawerContent = {
        Row(modifier = Modifier.fillMaxWidth()) {
                Column(
                    modifier = Modifier
                        .requiredWidth(250.dp)
                        .fillMaxHeight()
                        .background(
                            Color.White,
                            RoundedCornerShape(topEnd = 16.dp, bottomEnd = 16.dp)
                        )
                ) {
                    //Drawer Content
                }
                Spacer(
                    modifier = Modifier
                        .fillMaxSize()
                        .clickable(
                            interactionSource = MutableInteractionSource(),
                            indication = null
                        ) {
                            scope.launch {
                                if (drawerState.isOpen) {
                                    drawerState.close()
                                }
                            }
                        },
                )
            }
        },
        drawerContainerColor = Color.Transparent
    ) {
        //Main Content
    }
Priyank Jain
  • 727
  • 1
  • 10
  • 15
  • It works well and thanks very much. Although this work-around is already brilliant, since the transparent part actually still belongs to drawerContent, you can't close the drawer by clicking "outside of the drawer" as before, which may makes users feel weird. Could you provide some extra advice? Or it's just unachievable for the current version of ModalNavigationDrawer? – Eynnzerr Jul 06 '22 at 08:19
  • @Eynnzerr I have updated the answer with a tap to close on the background. – Priyank Jain Jul 06 '22 at 14:01
0

I have tweaked @Priyank-Jain's answer a little bit to clean up the elevation left behind by the original drawer. Remove the elevation from the original draw and add it to the newly created one

val scope = rememberCoroutineScope()

ModalNavigationDrawer(
   drawerState = drawerState,
   drawerContent = {
        Row(modifier = Modifier.fillMaxWidth()) {
                Surface(
                    modifier = Modifier
                        .requiredWidth(320.dp)
                        .fillMaxHeight(),
                    color = Color.White,
                    shape = RoundedCornerShape(topEnd = 16.dp, bottomEnd = 16.dp),
                    elevation = 16.dp
                ) {
                    //Drawer Content
                }
                Spacer(
                    modifier = Modifier
                        .fillMaxSize()
                        .clickable(
                            interactionSource = MutableInteractionSource(),
                            indication = null
                        ) {
                            scope.launch {
                                if (drawerState.isOpen) {
                                    drawerState.close()
                                }
                            }
                        },
                )
            }
        },
        drawerContainerColor = Color.Transparent,
        drawerElevation = 0.dp,
    ) {
        //Main Content
    }
Chad Gregory
  • 118
  • 4
  • 11
0

You can add padding to the end of the modalDrawersheet.

ModalNavigationDrawer(
   drawerState = drawerState,
   drawerContent = {
      ModalDrawerSheet(
         modifier = Modifier
             .padding (0.dp, 0.dp, 50.dp, 0.dp)
             .fillMaxHeight()
      ) {

         // drawer content
      }
   }
) 
0

ModalNavigationDrawer hardcodes the width of the content to be 360dp (as seen in the source). In order to override this, we can use requiredWidth() as follows:

ModalNavigationDrawer(
    drawerState = drawerState,
    content = underlyingContent,
    drawerContent = {
        ModalDrawerSheet(modifier = Modifier.requiredWidth(320.dp)) {
            // content
        }
    }
)
Samuel Ho
  • 66
  • 1
  • 6