Scaffold and the Navigation Drawer
Almost every app screen has the same frame: a bar at the top, content in the middle, maybe a round "+" button in the corner and a menu that slides in from the side. Placing all of that by hand is fiddly. Compose gives you Scaffold for the frame and ModalNavigationDrawer for the side menu.
The rule
Scaffold fills the slots; content honours the padding.
Scaffold has named slots for the standard parts of a screen:
Scaffold(
topBar = {
TopAppBar(
title = { Text("My plants") },
navigationIcon = {
IconButton(onClick = { scope.launch { drawerState.open() } }) {
Icon(Icons.Filled.Menu, contentDescription = "Open menu")
}
}
)
},
floatingActionButton = {
FloatingActionButton(onClick = onAdd) {
Icon(Icons.Filled.Add, contentDescription = "Add plant")
}
}
) { innerPadding ->
PlantList(Modifier.padding(innerPadding))
}The content lambda receives innerPadding: the space the bars take up. You must apply it, or your first list item hides under the top bar.
A navigation drawer holds the app's top-level destinations. ModalNavigationDrawer wraps the screen and slides over it when opened:
val drawerState = rememberDrawerState(DrawerValue.Closed)
val scope = rememberCoroutineScope()
ModalNavigationDrawer(
drawerState = drawerState,
drawerContent = { ModalDrawerSheet { SproutMenuItems() } }
) {
Scaffold(/* as above */) { /* ... */ }
}open() and close() animate the drawer, so they are suspend functions, launched from a coroutine scope.
The shortcut
Sketch the screen and label each region with its slot: top → topBar, corner button → floatingActionButton, middle → content, side menu → the drawer around everything.
Outermost
Side menu for top-level places →
ModalNavigationDrawer.
Drills
Answer fast — trust the rule.
Which Scaffold slot holds the round "+" button?
The first plant in the list is hidden under the top bar. What was forgotten?
Why is drawerState.open() called inside scope.launch { }?
What belongs in a navigation drawer?
Remember
- Scaffold fills the slots; content honours the padding.
- Label each region with its slot, and wrap the whole screen in the drawer.
- Drawer
open()andclose()suspend: call them from a coroutine scope.
