为何在LaunchedEffect中调用requireOffset仍导致应用崩溃?
解决Material3 BottomSheetScaffold实时编辑崩溃问题(获取滑动进度场景)
问题背景
在Material3的BottomSheetScaffold中,原Material版本的progress参数已被移除,于是通过requireOffset()方法获取偏移量来计算滑动进度值。但开启Android Studio实时编辑功能后,只要修改任意代码,应用就会崩溃,报错信息为尝试在初始化前获取偏移量。
问题原因
实时编辑触发Composable重组时,LaunchedEffect会在BottomSheet状态还未完全初始化的阶段就调用requireOffset(),而此时系统还未给BottomSheet分配有效偏移量,直接调用非空的requireOffset()就会抛出异常。另外初始用-1f标记初始偏移量的逻辑,在重组时可能重复执行,也会引发计算异常。
解决方案
- 使用可空的
offset替代requireOffset():offset是BottomSheetState的可空属性,未初始化时返回null,不会直接崩溃; - 用
derivedStateOf计算进度:基于BottomSheet的偏移量、peek高度和最大高度,通过derivedStateOf自动推导进度值,减少不必要的状态更新; - 直接基于已知高度计算进度:不再依赖首次偏移量初始化,改用peek高度和BottomSheet的最大展开高度作为计算基准,逻辑更稳定。
修改后的代码
@OptIn(ExperimentalMaterial3Api::class) @Composable fun PlayerViewBottomSheet(modifier: Modifier = Modifier) { val bottomSheetScaffoldState = rememberBottomSheetScaffoldState() val sheetState = bottomSheetScaffoldState.bottomSheetState val peekHeight = 70.dp val peekHeightPx = with(LocalDensity.current) { peekHeight.toPx() } // 计算滑动进度:0对应peek状态,1对应完全展开状态 val progress = remember(sheetState) { derivedStateOf { val currentOffset = sheetState.offset ?: return@derivedStateOf 0f val maxOffset = sheetState.maxValue - peekHeightPx // 进度值范围:0(收起)→1(完全展开) (maxOffset + currentOffset) / maxOffset } } BottomSheetScaffold( sheetPeekHeight = peekHeight, scaffoldState = bottomSheetScaffoldState, sheetDragHandle = null, sheetShadowElevation = 1.dp, sheetShape = RectangleShape, sheetContent = { BottomSheetContent( targetValue = sheetState.targetValue, currentValue = sheetState.currentValue, progress = progress.value ) } ) { MainScreen() } }
额外说明
derivedStateOf会自动感知依赖的sheetState.offset变化,只有当偏移量改变时才重新计算进度,避免无效重组;- 进度计算逻辑中,
maxOffset是BottomSheet从peek状态到完全展开状态的总偏移距离,通过currentOffset与maxOffset的比值得到0-1之间的进度值; - 移除了不必要的Experimental注解,只保留Material3相关的
ExperimentalMaterial3Api即可。
内容的提问来源于stack exchange,提问作者Prabh
相关产品推荐
相关产品推荐

