前言
文本的输入框架本身提供了
BasicTextField
TextField
OutlinedTextField
BasicTextField是最基本的输入框,没有什么样式,也方便我们自定义,是我们最常用的组件。
后两者有自带的样式和交互效果,但是实际项目中并不符合我们的效果,所以一般很少用。
使用过程中我们要注意两个问题
- 怎样收起键盘?
- 怎样在键盘显示的时候防止遮挡界面?
收起键盘
示例
1 |
|
两种方式
方式1
1 | // 获取焦点管理器(用于清除焦点) |
方式2
1 | // 可选:获取键盘控制器(用于强制收起键盘) |
核心实现原理
- 焦点管理:通过
LocalFocusManager获取焦点管理器,调用focusManager.clearFocus()可清除所有组件的焦点,输入框失去焦点后键盘会自动收起。 - 父布局可点击:将整个屏幕的父布局(如
Box)设置为clickable,点击时触发焦点清除操作。 - 事件冒泡:通过
pointerInput(Unit) {}确保点击事件能从子组件传递到父组件(避免子组件消费事件后父组件无法响应)。 - 可选:强制收起键盘:通过
LocalSoftwareKeyboardController的hide()方法可以强制收起键盘,适合某些特殊场景(如焦点清除后键盘未自动收起的情况)。
注意事项
- 确保父布局的
clickable修饰符作用于整个可点击区域(通常是fillMaxSize()的容器)。 - 输入框本身的点击事件不会触发父布局的
clickable(因为事件会被输入框优先消费),这符合预期(点击输入框时应保持焦点并弹出键盘)。 - 此方案适用于所有需要点击空白区域收起键盘的场景(不仅限于
BasicTextField,也适用于TextField等输入组件)。
键盘防遮挡
在 Jetpack Compose 中,当软键盘(IME)弹出时遮挡输入框(如 TextField)是一个常见问题。
Android 系统本身会尝试滚动或调整窗口,但在 Compose 中需要配合正确的配置和布局策略才能确保输入框始终可见。
三步解决键盘遮挡问题
设置windowSoftInputMode
在 AndroidManifest.xml 中设置 windowSoftInputMode
这是最关键的一步!Compose 本身无法控制 IME 行为,必须由 Activity 配合。
1 | <activity |
- ✅
adjustResize:Activity 的窗口会被压缩(不是平移),为键盘腾出空间。 - ❌ 避免使用
adjustPan(它只平移,不压缩,容易导致布局错乱)。
设置imePadding
使用 imePadding() + 可滚动容器
即使设置了 adjustResize,如果内容不可滚动,底部的 TextField 仍可能被键盘盖住。
你需要:
- 包裹内容在可滚动容器中(如
LazyColumn或verticalScroll) - 在底部添加
imePadding()
注意
如果空白空间足够显示弹窗,可以不用在滚动容器中,只设置
Modifier.imePadding()
使用 LazyColumn
1 |
|
使用 Column + verticalScroll
1 |
|
imePadding()会自动监听 IME 显示/隐藏,并动态添加padding.bottom = 键盘高度。
自动滚动到输入框(可选)
如果输入框不在可视区域,可以在获得焦点时自动滚动到底部。
方法:使用 bringIntoViewRequester
1 |
|
💡 注意:
bringIntoView()在某些版本 Compose 中对verticalScroll支持有限,更可靠的方式是直接滚动到底部:
1 | LaunchedEffect(Unit) { |
常见错误排查
| 问题 | 解决方案 |
|---|---|
设置了 imePadding() 但没效果 |
检查 AndroidManifest.xml 是否有 adjustResize |
使用 Box 或 ConstraintLayout 包裹 |
改用 Column/LazyColumn + verticalScroll |
| 全屏模式(沉浸式)导致 IME 不触发 resize | 避免使用 WindowInsetsControllerCompat 隐藏状态栏/导航栏,或手动处理 insets |
使用 Dialog 或 BottomSheet |
它们默认不响应 adjustResize,需手动监听 WindowInsets.ime |
手动监听 IME 高度(备用方案)
如果 imePadding() 不满足需求,可手动获取 IME 高度:
1 | val imeHeight = WindowInsets.ime.getBottom(LocalDensity.current) |
但通常 imePadding() 已足够。
总结
要让 Compose 输入框不被键盘遮挡,请按顺序检查:
- ✅
AndroidManifest.xml中 Activity 设置android:windowSoftInputMode="adjustResize" - ✅ 布局使用可滚动容器(
LazyColumn或verticalScroll) - ✅ 在容器上加
.imePadding()