TL;DR: soft keyboard should overlap a bottom-anchored view instead of pushing it up. Gitlab link for an mcve.
Summary:
I have an AppCompatDialogFragment
(androidx) which appears fullscreen on phones and has fixed dimensions on tablets (using dialog?.window?.setLayout(width, height)
in case this matters). The dialog's layout has some content placed in a ScrollView
and a button-like layout anchored at the bottom (complete XML structure see below).
Side note: the superclass of the AppCompatDialogFragment
in question calls setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN)
on its Window
.
The problem:
When the soft keyboard appears as a result of some text input receiving focus, it pushes the complete layout up, including the bottom-anchored view that I want overlapped by the soft keyboard. For some reason, the issue only affects phones, on tablets the soft keyboard correctly overlaps everything including the bottom-anchored view without any additional adjustments or flags.
What I have tried (without any success):
android:windowSoftInputMode="adjustNothing"
(tried other flags "just in case" as well) for the Activity
in question, also tried to apply them in codeandroid:isScrollContainer="false"
on the ScrollView
and its parentHere's the layout in question (note: I omitted many unrelated attributes to keep the snippet reasonably sized; everything is positioned vertically matching the elements' order. The <include>
elements contain the text inputs):
<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>
The question: how do I force the soft keyboard to overlap the layout anchored at the bottom on all devices?
Please comment if you need any additional details.
EDIT: here's a minimal demo app that reproduces the issue: https://gitlab.com/Droidman/soft-keyboard-issue-demo
Try adding the following line to onCreateView()
of DemoDialog
:
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING)
It is important to apply this change to the window of the dialog and not to the window of the activity.
With this in place, this is what I see on an Nexus 6 emulator running API 29 using your MCVE:
You may need to work with the placement a little, but this should help.
Let's look under the hood a little. For a phone and a tablet, the soft input mode is zero in onCreateView()
. This value corresponds to SOFT_INPUT_ADJUST_UNSPECIFIED. The documentation for SOFT_INPUT_ADJUST_PAN explains what happens when the soft input mode is unspecified (emphasis is mine.)
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.
Looking at the value of the soft input mode in onStart()
(dialog?.window?.attributes?.softInputMode
) shows the value selected by the system for the phone is SOFT_INPUT_ADJUST_RESIZE) and the value selected for the tablet is SOFT_INPUT_ADJUST_PAN. This explains the difference that is seen between phones and tablets.
So, always setting the soft input mode to SOFT_INPUT_ADJUST_PAN
looks like the best solution although SOFT_INPUT_ADJUST_NOTHING
also works and may be preferable for certain layouts.