描述问题的最佳方式是视频:
https://www.youtube.com/watch?v=6ZY5zIaK82g
视频是在 Android 13 手机上录制的,在 Android 14 手机和模拟器上也有相同的行为。
在上面的视频中,您可以看到键盘和缩进的行为很奇怪,即: 缩进通常略小于键盘的高度;有时,即使关闭键盘后,压痕仍然存在;有时打开键盘后,屏幕底部的填充仍然很小;并且几乎总是关闭后键盘再次闪烁,然后才关闭。
我的代码:
MainActivity.kt:
package com.samp.gui
import android.os.Bundle
import androidx.activity.enableEdgeToEdge
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.WindowInsets
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.ime
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.windowInsetsBottomHeight
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.TextField
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.ComposeView
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
val windowInsetsController =
WindowCompat.getInsetsController(window, window.decorView)
windowInsetsController.systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
windowInsetsController.hide(WindowInsetsCompat.Type.systemBars())
WindowCompat.setDecorFitsSystemWindows(window, false)
val composeView = ComposeView(this)
setContentView(composeView)
composeView.setContent {
val scrollState = rememberLazyListState()
LazyColumn(
modifier = Modifier
.background(Color.Red)
.fillMaxSize(),
state = scrollState
) {
item {
Column(
modifier = Modifier
.fillParentMaxSize()
.background(Color.Green)
) {
Box(Modifier.fillMaxSize()) {
var text by remember {
mutableStateOf("")
}
TextField(
modifier = Modifier.align(Alignment.TopCenter),
value = text,
onValueChange = { text = it },
singleLine = true
)
}
}
}
item {
Spacer(Modifier.imePadding())
}
}
}
}
}
我使用AppCompatActivity的原因是因为主应用程序正在迁移到compose。使用LazyColumn的原因是有fillParentMaxSize,没有它里面的组件将无法填满整个屏幕。
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.Gui"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.Gui"
android:screenOrientation="sensorLandscape"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
主题.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Theme.Gui" parent="@style/Theme.AppCompat.NoActionBar">
<item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
</style>
</resources>
除了 imePadding 我测试了 ViewCompat.getRootWindowInsets(view).getInsets(WindowInsetsCompat.Type.ime()) 和 Modifier.windowInsetsBottomHeight(WindowInsets.ime) 都与视频上的 imePadding 相同
使用LazyColumn的原因是要有
,没有它里面的组件就无法填满整个屏幕。fillParentMaxSize
fillParentMaxSize()
修改器存在,因此您可以使 LazyColumn
的每个项目与 LazyColumn
的大小一样大。仅仅为了拥有这个修饰符而使用 LazyColumn
是没有意义的。
您尚未指定 UI 的外观,但如果您只想显示 TextField 并确保键盘不与其重叠,请像您已经做的那样使用
fillMaxSize()
修饰符:
composeView.setContent {
var text by remember {
mutableStateOf("")
}
Column(
modifier = Modifier
.fillMaxSize()
.imePadding(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Start
) {
TextField(
value = text,
onValueChange = { text = it },
singleLine = true
)
}
}
这应该会产生与当前代码相同的布局。键盘永远不会与文本字段重叠。
Column
的官方文档。