Jetpack Compose imePadding ведёт себя крайне странно, оставаясь после закрытия клавиатуры и вызывает глюки клавиатуры
Записал видео с этим поведением:
https://www.youtube.com/watch?v=6ZY5zIaK82g
Видео записывал на телефоне с Андроид 13, такое же поведение было на другом телефоне и эмуляторе с Андроид 14
В видео есть сразу несколько багов которые я замечал при использовании imePadding:
- Отступ часто меньше по высоте. чем сама клавиатура
- Иногда отступ остаётся на месте, даже если клавиатура закрыта
- Иногда отступ это просто мелкая красная полоска в нижней части экрана
- И почти всегда клавиатура показывается ещё раз на секунду, после закрытия. Такое же поведение было и без LazyColumn вместе с adjustPan. Вообще такое поведение встречаю во всех возможных конфигурациях. Это баг compose или я что-то не так делаю?
Мой код:
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, чтобы первый блок всегда заливал весь экран, а второй был только отступ для клавиатуры. Так можно залить весь фон одним цветом, для красоты, чтобы не было чёрных отступов по бокам клавиатуры. Обычная Column с scrollable не даёт 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>
С adjustPan вместо adjustResize и без LazyColumn всё работает чуть лучше, но видны чёрные полосы по бокам. При этом баг с показывающейся на секунду клавиатурой остаётся.
themes.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) все дают такое же поведение, как и на видео