How to slide the contents of scaffold when drawers open. Similar to this question but in jetpack compose.
Asked
Active
Viewed 911 times
1 Answers
5
I found a solution...
// This is optional if you need to open/close the drawer programmatically
val coroutineScope = rememberCoroutineScope()
// We need the drawer state to check:
// 1. if it is opened or closed
// 2. request to open/close it
// 3. get the drawer's offset (and do the slide of the content)
val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed)
// Drawer's width. It will be updated later in LaunchedEffect
var drawerWidth by remember {
mutableStateOf(drawerState.offset.value)
}
// As soon the user move the drawer, the content must move in sync.
// So here we're creating a derived state of the drawer state
// to update the content position.
val contentOffset = remember {
derivedStateOf {
drawerState.offset.value
}
}
// The scaffold state contains the drawer state.
val scaffoldState = rememberScaffoldState(
drawerState = drawerState
)
Scaffold(
scaffoldState = scaffoldState,
drawerContent = {
Box {
// your drawer content here...
}
}
) {
Box(Modifier.fillMaxSize()) {
// Here's the content's offset calculation logic
val xPos = (abs(drawerWidth) - abs(contentOffset.value))
Column(
// Set the content's offset
Modifier.offset(
x = with(LocalDensity.current) {
max(0.dp, xPos.toDp() - 56.dp)
}
)
) {
// Optional: opening the drawer using a button
Button(onClick = {
coroutineScope.launch {
drawerState.open()
}
}) {
Text("Open Drawer")
}
}
}
}
// Important! Initializing the drawerWidth
SideEffect {
if (drawerWidth == 0f) {
drawerWidth = drawerState.offset.value
}
}
Here's the result:
Warning! This solution has a problem: as you can see, I'm using a hardcoded value 56.dp
. This is because the Material Design library uses this value as end padding of the drawer. You can see this constant in the Drawer.kt
file in Material Design library.
private val EndDrawerPadding = 56.dp

nglauber
- 18,674
- 6
- 70
- 75
-
1All credit to you for the idea and for teaching me this cool kotlin trick with ```with``` blocks. But it seems to me like if the 56dp is already baked in, then drawerWidth is just a proxy for screen width, which requires very little maneuvering. So I opted to use ```.offset(x = max(0.dp,with(LocalDensity.current){(LocalConfiguration.current.screenWidthDp.dp + scaffoldState.drawerState.offset.value.toDp()-56.dp)}))``` – D. Kupra Jan 12 '22 at 06:42