确定键盘是否存在并在 Jetpack Compose 中相应地更改布局

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

当我单击 TextField 时,我需要向上滚动 UI 以向用户显示登录按钮,而不是将其隐藏在键盘后面。

我正在使用 RelocationRequester 来实现同样的目的。

我用它来检测键盘显示/隐藏事件:

fun listenKeyboard() {
val activityRootView =
  (requireActivity().findViewById<View>(android.R.id.content) as ViewGroup).getChildAt(0)
activityRootView.viewTreeObserver.addOnGlobalLayoutListener(object :
  ViewTreeObserver.OnGlobalLayoutListener {
  private var wasOpened = false
  private val DefaultKeyboardDP = 100
  private val EstimatedKeyboardDP =
    DefaultKeyboardDP + 48
  private val r: Rect = Rect()
  override fun onGlobalLayout() {
    val estimatedKeyboardHeight = TypedValue
      .applyDimension(
        TypedValue.COMPLEX_UNIT_DIP,
        EstimatedKeyboardDP.toFloat(),
        activityRootView.resources.displayMetrics
      )
      .toInt()

    activityRootView.getWindowVisibleDisplayFrame(r)
    val heightDiff: Int = activityRootView.rootView.height - (r.bottom - r.top)
    val isShown = heightDiff >= estimatedKeyboardHeight
    if (isShown == wasOpened) {
      return
    }
    wasOpened = isShown
    keyboardVisibleState(isShown)
  }
})
  }

一旦键盘可见,我就会调用 relocationRequestor 的 BringIntoView()。

coroutineScope.launch {     
    delay(250)
    relocationRequester.bringIntoView()
}

它的行为随机,在某些设备上工作,在其他设备上不工作。有没有更好的解决方案来解决这个问题?

android scroll android-jetpack-compose
3个回答
14
投票

Compose 1.2.0 起,Accompanist Insets 大部分移至 Compose Foundation 中,请查看 迁移指南 了解更多详细信息。以下答案的主要变化是不再需要

ProvideWindowInsets
,并且应该替换一些导入。


您可以使用伴奏插图。您可以使用

LocalWindowInsets.current.ime.isVisible
检查键盘是否显示,或将
.imePadding()
添加到屏幕容器中。

这个效果很好。但要使其正常工作,您必须禁用窗户装饰配件:

该库不会禁用窗户装饰配件。为了使您的视图层次结构能够接收插图,您需要确保从您的 Activity 中调用:WindowCompat.setDecorFitsSystemWindows(window, false)。您还需要将系统栏背景设置为透明,这可以使用我们的系统 UI 控制器库来完成。

如果您不想这样做,则必须寻找其他解决方案。


onCreate
中的示例:

WindowCompat.setDecorFitsSystemWindows(window, false)

setContent {
    ProvideWindowInsets {
        ComposePlaygroundTheme {
            Column(
                horizontalAlignment = Alignment.CenterHorizontally,
                modifier = Modifier
                    .fillMaxWidth()
                    .statusBarsPadding()
                    .navigationBarsWithImePadding()
                    .padding(10.dp)
            ) {
                TextField(value = "", onValueChange = {})
                Spacer(Modifier.weight(1f))
                Button(onClick = {}) {
                    Text(text = "Proceed")
                }
            }
        }
    }
}


附注此外,这对惰性视图没有帮助:它会减小容器大小,但不会滚动到所选项目。等待这个问题解决


6
投票

编辑 2024 年 7 月:

现在可以使用

WindowInsets.isImeVisible
imeAnimationSource
imeAnimationTarget

请参阅下文 2022 年 3 月的答案。


由于伴奏者的插图已被弃用,因此应使用

androidx.compose.foundation
处的插图。

我可以使用

WindowInsets.Companion.ime.getBottom(LocalDensity.current) > 0
检查 IME 是否显示。否则,如果更适合您的用例,也可以使用
Modifier.imePadding()
。我不确定这是否适用于横向模式和其他奇怪的键盘组合,但它似乎可以在带有“底部”键盘的纵向模式下工作。

此的“官方”API 仍处于功能请求阶段,位于问题跟踪器上:https://issuetracker.google.com/issues/217770337


0
投票

您也可以将以下行添加到活动部分的清单中:

android:windowSoftInputMode =“调整调整大小”

就像这个例子:

        <activity
        android:name=".MainActivity"
        android:exported="true"
        android:label="@string/app_name"
        android:windowSoftInputMode="adjustResize"
        android:theme="@style/Theme.MyApp">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

        <meta-data
            android:name="android.app.lib_name"
            android:value="" />
        </activity>
© www.soinside.com 2019 - 2024. All rights reserved.