Jetpack Compose 中打开抽屉时如何滑动平移 Scaffold 内容
Jetpack Compose 实现侧边抽屉打开时平移Scaffold内容的方案
实现思路
原生Scaffold默认的抽屉效果是覆盖在主内容上方,要实现抽屉展开时推挤主内容平移的效果,不需要自定义复杂的抽屉组件,直接复用官方抽屉状态监听逻辑即可:
- 用官方提供的
DrawerState监听抽屉的展开进度,无需自定义状态变量 - 根据抽屉的展开进度计算主内容的水平偏移量,最大偏移量可自定义为抽屉的宽度
- 给Scaffold添加偏移修饰符,让主内容的偏移跟随抽屉进度实时变化,实现平滑联动效果
核心实现代码
@OptIn(ExperimentalMaterial3Api::class) @Composable fun PushContentDrawerDemo() { // 初始化抽屉状态和协程作用域 val drawerState = rememberDrawerState(initialValue = DrawerValue.Closed) val scope = rememberCoroutineScope() // 自定义抽屉宽度,可根据需求调整 val drawerWidth = 300.dp // 计算主内容最大偏移像素值 val maxContentOffset = with(LocalDensity.current) { drawerWidth.toPx() } ModalNavigationDrawer( drawerState = drawerState, drawerContent = { // 抽屉内容布局 ModalDrawerSheet(modifier = Modifier.width(drawerWidth)) { Text("菜单项1", modifier = Modifier.padding(vertical = 16.dp, horizontal = 24.dp)) Text("菜单项2", modifier = Modifier.padding(vertical = 16.dp, horizontal = 24.dp)) Text("菜单项3", modifier = Modifier.padding(vertical = 16.dp, horizontal = 24.dp)) } } ) { Scaffold( topBar = { TopAppBar( title = { Text("主页") }, navigationIcon = { IconButton(onClick = { scope.launch { if (drawerState.isOpen) drawerState.close() else drawerState.open() } }) { Icon(Icons.Default.Menu, contentDescription = "打开抽屉") } } ) }, // 核心逻辑:绑定主内容偏移和抽屉展开进度 modifier = Modifier.graphicsLayer { translationX = drawerState.offset.value.coerceAtLeast(0f) } ) { innerPadding -> // 主内容布局 Box( modifier = Modifier .fillMaxSize() .padding(innerPadding) ) { Text("主页面内容", modifier = Modifier.align(Alignment.Center)) } } } }
注意事项
- 如果你使用的是Material2版本的Compose组件,将
ModalNavigationDrawer替换为Drawer组件即可,状态监听逻辑完全一致 - 使用
graphicsLayer设置偏移比使用offset修饰符性能更好,不需要反复做px和dp的单位转换,且默认开启硬件加速 - 如果需要额外增加动效,可以在
graphicsLayer中添加缩放、圆角属性,示例:scaleX = 1f - (drawerState.offset.value / maxContentOffset * 0.1f),即可实现内容右移同时轻微缩小的效果 - 部分低版本Compose中
drawerState.offset不可用,可以用(if (drawerState.isOpen) 1f else 0f)配合animateFloatAsState实现过渡动画,效果一致
内容的提问来源于stack exchange,提问作者sunny52525
相关产品推荐
相关产品推荐

