如何强制软输入与底部锚定视图重叠?

How to force the soft input to overlap bottom-anchored View?

TL;DR: 软键盘应该与底部锚定视图重叠,而不是将其向上推。 Gitlab link for an mcve.

总结:

我有一个 AppCompatDialogFragment (androidx),它在手机上显示 全屏,在平板电脑上具有 固定尺寸(使用 dialog?.window?.setLayout(width, height) 万一这很重要)。对话框的布局有一些内容放在 ScrollView 中,还有一个类似按钮的布局固定在底部(完整的 XML 结构见下文)。

旁注:有问题的 AppCompatDialogFragment 的超类在其 Window.

上调用 setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)

问题:

当软键盘由于某些文本输入获得焦点而出现时,它会将整个布局向上推,包括我希望与软键盘重叠的底部锚定视图。出于某种原因,该问题仅影响手机,在平板电脑上,软键盘正确地覆盖了所有内容,包括底部锚定视图,没有任何额外的调整或标记。

我尝试过的(没有成功):

这是有问题的布局(注意:我省略了许多不相关的属性以保持代码段的合理大小;所有内容都垂直放置以匹配元素的顺序。<include> 元素包含文本输入):

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.appcompat.widget.Toolbar         
        android:layout_width="match_parent"
        android:id="@+id/toolbar"
        android:layout_height="?attr/actionBarSize"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="0dp"
        app:layout_constraintBottom_toTopOf="@id/bottom_layout"
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        android:isScrollContainer="false"
        android:scrollbarStyle="outsideOverlay">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

            <include
                layout="@layout/some_layout_1"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

            <include
                layout="@layout/some_layout_2"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"/>

        </androidx.constraintlayout.widget.ConstraintLayout>
    </ScrollView>

  <!-- I want this one to be overlapped by the soft input, but it's just pushed up -->
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/bottom_layout"
        app:layout_constraintBottom_toBottomOf="parent">

        <View
            android:layout_width="match_parent"
            android:layout_height="@dimen/divider"
            android:background="@color/dark_grey" />

        <TextView
            android:layout_width="match_parent"
            android:layout_height="@dimen/some_dimen"
            android:foreground="?attr/selectableItemBackground"
            android:text="@string/text" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

问题:如何强制软键盘与所有设备底部锚定的布局重叠?

如果您需要任何其他详细信息,请发表评论。

编辑:这是重现问题的最小演示应用程序:https://gitlab.com/Droidman/soft-keyboard-issue-demo

将此添加到 class 中的 AndroidManifest 标签内 Class:

android:windowSoftInputMode="stateHidden|adjustResize"

尝试将以下行添加到 DemoDialogonCreateView()

dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)

重要的是将此更改应用于对话框的 window,而不是 activity 的 window。

有了这个,这就是我在 Nexus 6 模拟器上看到的 运行 API 29 使用你的 MCVE:

您可能需要稍微处理一下展示位置,但这应该会有所帮助。


让我们深入了解一下。对于 phone 和平板电脑,软输入模式在 onCreateView() 中为零。这个值对应SOFT_INPUT_ADJUST_UNSPECIFIED. The documentation for SOFT_INPUT_ADJUST_PAN解释了当未指定软输入模式时会发生什么(强调是我的。)

Adjustment option for softInputMode : set to have a window pan when an input method is shown, so it doesn't need to deal with resizing but just panned by the framework to ensure the current input focus is visible. This can not be combined with SOFT_INPUT_ADJUST_RESIZE ; if neither of these are set, then the system will try to pick one or the other depending on the contents of the window.

查看onStart()(dialog?.window?.attributes?.softInputMode)中软输入模式的值可知phone系统选择的值为SOFT_INPUT_ADJUST_RESIZE) and the value selected for the tablet is SOFT_INPUT_ADJUST_PAN。这解释了 phones 和平板电脑之间的差异。

因此,始终将软输入模式设置为 SOFT_INPUT_ADJUST_PAN 看起来是最佳解决方案,尽管 SOFT_INPUT_ADJUST_NOTHING 也可以工作并且对于某些布局可能更可取。