Material3 1.1.2中键盘推高ModalBottomSheet异常问题求助
Material3 1.1.2 ModalBottomSheet 键盘唤起内容异常上推问题解决方案
问题描述
使用Material3 1.1.2版本时,非全屏高度的ModalBottomSheet(如示例中300dp高度)唤起软键盘后,Sheet内容会被推至预期高度的2倍以上,收起键盘后padding恢复正常。1.2.0-beta版本已修复该bug,但beta版本存在其他无法接受的问题,因此需要在1.1.2版本中找到替代方案。
已尝试以下操作均无效:
- 修改
setSoftInputMode - 添加
imePadding或safePadding修饰符 - 仅全屏ModalBottomSheet可正常工作,但不符合需求
问题示意图:
复现代码:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun Greeting(name: String, modifier: Modifier = Modifier) { var showModal = remember { mutableStateOf(false) } val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) var message by rememberSaveable { mutableStateOf("") } Box(modifier = Modifier.fillMaxSize()) { Button( modifier = Modifier.height(42.dp), onClick = { showModal.value = true }) { Text(text = "expand modal") } } if (showModal.value) { ModalBottomSheet( sheetState = bottomSheetState, dragHandle = null, onDismissRequest = { showModal.value = false } ) { Box( modifier = Modifier .height(300.dp) .padding(bottom = 32.dp), contentAlignment = Alignment.BottomCenter ) { Row( modifier = Modifier .padding( start = 16.dp, end = 16.dp, bottom = 16.dp ) .fillMaxWidth() .wrapContentHeight(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { BasicTextField( value = message, onValueChange = { newValue -> message = newValue }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Default ), textStyle = TextStyle(color = Color.Black), cursorBrush = SolidColor(Color.Black) ){ innerTextField -> Row( modifier = Modifier .fillMaxWidth() .border( width = 2.dp, color = Color.Gray, shape = RoundedCornerShape(size = 16.dp) ) .padding(8.dp) ) { innerTextField() } } } } } } }
可行解决方案
方案一:自定义WindowInsets避免重复padding叠加
通过覆盖ModalBottomSheet默认的WindowInsets,手动添加一次IME padding,避免默认逻辑重复计算导致的异常上推:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun FixedGreeting(name: String, modifier: Modifier = Modifier) { var showModal = remember { mutableStateOf(false) } val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) var message by rememberSaveable { mutableStateOf("") } // 自定义空Insets,禁用ModalBottomSheet默认的IME padding处理 val customWindowInsets = remember { WindowInsets(0, 0, 0, 0) } Box(modifier = Modifier.fillMaxSize()) { Button( modifier = Modifier.height(42.dp), onClick = { showModal.value = true }) { Text(text = "expand modal") } } if (showModal.value) { ModalBottomSheet( sheetState = bottomSheetState, dragHandle = null, onDismissRequest = { showModal.value = false }, windowInsets = customWindowInsets ) { Box( modifier = Modifier .height(300.dp) .padding(bottom = 32.dp) .imePadding(), // 手动添加一次IME padding contentAlignment = Alignment.BottomCenter ) { // 原内容保持不变 Row( modifier = Modifier .padding( start = 16.dp, end = 16.dp, bottom = 16.dp ) .fillMaxWidth() .wrapContentHeight(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { BasicTextField( value = message, onValueChange = { newValue -> message = newValue }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Default ), textStyle = TextStyle(color = Color.Black), cursorBrush = SolidColor(Color.Black) ){ innerTextField -> Row( modifier = Modifier .fillMaxWidth() .border( width = 2.dp, color = Color.Gray, shape = RoundedCornerShape(size = 16.dp) ) .padding(8.dp) ) { innerTextField() } } } } } } }
方案二:监听键盘状态动态调整Sheet高度
通过监听键盘可见性,动态调整ModalBottomSheet内容的高度,抵消异常上推的影响:
@OptIn(ExperimentalMaterial3Api::class) @Composable fun FixedGreeting2(name: String, modifier: Modifier = Modifier) { var showModal = remember { mutableStateOf(false) } val bottomSheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true) var message by rememberSaveable { mutableStateOf("") } val keyboardController = LocalSoftwareKeyboardController.current val isKeyboardVisible = remember { mutableStateOf(false) } val windowInsets = LocalWindowInsets.current // 监听键盘显示/隐藏状态 DisposableEffect(windowInsets.ime) { val listener = InsetsListener { insets -> isKeyboardVisible.value = insets.bottom > 0 } windowInsets.ime.addListener(listener) onDispose { windowInsets.ime.removeListener(listener) } } Box(modifier = Modifier.fillMaxSize()) { Button( modifier = Modifier.height(42.dp), onClick = { showModal.value = true }) { Text(text = "expand modal") } } if (showModal.value) { ModalBottomSheet( sheetState = bottomSheetState, dragHandle = null, onDismissRequest = { showModal.value = false keyboardController?.hide() } ) { Box( modifier = Modifier .height( if (isKeyboardVisible.value) { // 键盘唤起时,按比例调整Sheet高度(可根据实际情况修改数值) 300.dp - (windowInsets.ime.currentValue.bottom / 2).dp } else { 300.dp } ) .padding(bottom = 32.dp), contentAlignment = Alignment.BottomCenter ) { // 原内容保持不变 Row( modifier = Modifier .padding( start = 16.dp, end = 16.dp, bottom = 16.dp ) .fillMaxWidth() .wrapContentHeight(), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.Center ) { BasicTextField( value = message, onValueChange = { newValue -> message = newValue }, keyboardOptions = KeyboardOptions( keyboardType = KeyboardType.Text, imeAction = ImeAction.Default ), textStyle = TextStyle(color = Color.Black), cursorBrush = SolidColor(Color.Black) ){ innerTextField -> Row( modifier = Modifier .fillMaxWidth() .border( width = 2.dp, color = Color.Gray, shape = RoundedCornerShape(size = 16.dp) ) .padding(8.dp) ) { innerTextField() } } } } } } }
方案三:移植官方修复逻辑
如果上述方案无法满足需求,可以参考Material3 1.2.0-beta中修复该问题的代码,手动修改ModalBottomSheet的Insets处理逻辑,核心是避免在非全屏Sheet中重复应用IME padding。
内容的提问来源于stack exchange,提问作者DroidPest
相关产品推荐
相关产品推荐

