You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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可正常工作,但不符合需求

问题示意图:
键盘唤起后Modal被异常上推

复现代码:

@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 12:50:57