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

Compose UI中键盘弹出时ModalBottomSheet上移过度的解决方法

解决Compose中ModalBottomSheet被键盘过度上移的问题

方案一:修改windowSoftInputMode为adjustResize并适配Insets

你当前配置的adjustPan模式会让整个窗口随键盘上移,加上透明系统栏的布局计算逻辑,容易导致ModalBottomSheet过度上移。改成adjustResize后,系统会调整窗口大小而非整体上移,再通过Compose的Insets控制Sheet的底部padding,只预留导航栏空间、排除键盘Insets即可解决:

  1. 先修改Manifest配置:
android:windowSoftInputMode="adjustResize"
  1. 在Compose Activity中启用边缘到边缘适配并处理Insets:
class YourActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge() // 启用边缘到边缘适配
        setContent {
            YourTheme {
                // 仅获取导航栏底部Insets,排除键盘Insets
                val navigationBarInsets = rememberWindowInsets(
                    WindowInsetsSides.Bottom,
                    exclude = WindowInsetsSides.Ime
                )
                val bottomPadding = navigationBarInsets.getInsets(WindowInsetsSides.Bottom).bottom.dp

                val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
                ModalBottomSheetLayout(
                    sheetState = sheetState,
                    sheetContent = {
                        Column(
                            modifier = Modifier
                                .fillMaxWidth()
                                .padding(bottom = bottomPadding)
                                .padding(horizontal = 16.dp)
                        ) {
                            // Sheet内的输入框及其他内容
                            OutlinedTextField(
                                value = "",
                                onValueChange = {},
                                label = { Text("输入内容") }
                            )
                            // 其他组件...
                        }
                    }
                ) {
                    // 主界面触发按钮
                    Button(onClick = { /* 显示Sheet逻辑 */ }) {
                        Text("打开底部弹窗")
                    }
                }
            }
        }
    }
}

方案二:保留adjustPan,动态限制Sheet高度

如果不想修改windowSoftInputMode,可以通过监听键盘显示状态,动态调整ModalBottomSheet的最大高度,避免过度上移:

class YourActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            YourTheme {
                val sheetState = rememberModalBottomSheetState(ModalBottomSheetValue.Hidden)
                val isKeyboardVisible = remember { mutableStateOf(false) }
                val window = remember { window }

                // 监听键盘显示状态
                DisposableEffect(Unit) {
                    val layoutListener = ViewTreeObserver.OnGlobalLayoutListener {
                        val displayFrame = Rect()
                        window.decorView.getWindowVisibleDisplayFrame(displayFrame)
                        val screenHeight = window.decorView.rootView.height
                        // 键盘高度超过屏幕15%判定为显示状态
                        val keyboardHeight = screenHeight - displayFrame.bottom
                        isKeyboardVisible.value = keyboardHeight > screenHeight * 0.15
                    }
                    window.decorView.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)
                    onDispose {
                        window.decorView.viewTreeObserver.removeOnGlobalLayoutListener(layoutListener)
                    }
                }

                ModalBottomSheetLayout(
                    sheetState = sheetState,
                    sheetContent = {
                        Column(
                            modifier = Modifier
                                .fillMaxWidth()
                                // 键盘显示时限制Sheet最大高度
                                .heightIn(max = if (isKeyboardVisible.value) 300.dp else 400.dp)
                                .padding(16.dp)
                        ) {
                            OutlinedTextField(
                                value = "",
                                onValueChange = {},
                                label = { Text("输入内容") }
                            )
                        }
                    }
                ) {
                    Button(onClick = { /* 显示Sheet逻辑 */ }) {
                        Text("打开底部弹窗")
                    }
                }
            }
        }
    }
}

方案三:自定义BottomSheetBehavior(混合场景适用)

如果项目是View与Compose混合开发,可通过自定义BottomSheetBehavior忽略键盘Insets:

class CustomBottomSheetBehavior<V : View>(context: Context, attrs: AttributeSet) :
    BottomSheetBehavior<V>(context, attrs) {
    override fun calculateInsets(rootView: View, insets: WindowInsetsCompat, outInsets: Rect) {
        // 仅处理导航栏Insets,排除键盘
        val navigationBarInsets = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
        outInsets.set(0, 0, 0, navigationBarInsets.bottom)
    }
}

之后在布局中使用该自定义Behavior,再通过ComposeView嵌入Sheet内容即可。


内容的提问来源于stack exchange,提问作者Farooq Arshed

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 12:05:01