Jetpack Compose imePadding 不提供统一的填充并导致键盘行为出现故障

问题描述 投票:0回答:1

描述问题的最佳方式是视频:

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 相同

android android-jetpack-compose android-softkeyboard
1个回答
0
投票

使用LazyColumn的原因是要有

fillParentMaxSize
,没有它里面的组件就无法填满整个屏幕。

在您的情况下,您可能不应该使用 LazyColumn。

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
的官方文档。

© www.soinside.com 2019 - 2024. All rights reserved.