The use and principle of Android soft keyboard windowSoftInputMode (use)

foreword

After reading many articles on the Internet, they did not explain the functions of several modes of windowSoftInputMode very accurately, and most of the articles only analyzed how to use them without in-depth analysis of the source code to analyze the principles. Today this article will analyze the functions and principles of each mode of the Android soft keyboard windowSoftInputMode.

1. Model introduction

android:windowSoftInputMode=["stateUnspecified",
                                       "stateUnchanged", "stateHidden",
                                       "stateAlwaysHidden", "stateVisible",
                                       "stateAlwaysVisible", "adjustUnspecified",
                                       "adjustResize", "adjustPan"]

As above, windowSoftInputMode has six stateXXX values ​​and three adjustXXX values. Simply put, the value prefixed by state controls the visibility of the software input method when the Activity becomes the user's focus, and the prefix prefixed by adjust controls how it is displayed in the window.
Both values ​​can be used in combination.
There are two types of visibility: hiding and displaying.
There are two display methods: when the soft window pops up, either shrink the content part, or adjust the position of the content so that the focus control is within the visible window.
The meaning of each value is as follows (official)

value illustrate
"stateUnspecified" The state of the soft keyboard (hidden or visible) is not specified. It will be up to the system to choose the appropriate state, or rely on the setting in the theme.

This is the default setting for soft keyboard behavior.

stateUnchanged Preserves whatever state the soft keyboard was last in when the Activity comes to the foreground, whether visible or hidden.
stateHidden When the user selects an activity—that is, when the user actually navigates forward into the activity, rather than returning from leaving another activity—hide the soft keyboard.
stateAlwaysHidden Always hide the soft keyboard when the Activity's main window has input focus.
stateVisible When the user selects an activity—that is, when the user actually navigates forward into the activity, rather than returning from leaving another activity—display the soft keyboard.
stateAlwaysVisible Always show the soft keyboard when the Activity's main window has input focus.
adjustUnspecified Does not specify whether the activity's main window resizes to make room for the soft keyboard, or whether the window contents pan to reveal the current focus on the screen. The system automatically selects one of these modes based on whether the contents of the window have any layout views that can scroll their contents. If such a view exists, the window will resize, provided that all of the window's contents can be seen within a smaller area by scrolling.

This is the default setting for the behavior of the main window.

adjustResize Always resize the activity's main window to make room for the on-screen soft keyboard.
adjustPan Instead of adjusting the size of the main window of the Activity to make room for the soft keyboard, the content of the window is automatically panned so that the current focus is never covered by the keyboard, so that the user can always see the content they input. This is generally less desirable than resizing, since the user may need to close the soft keyboard to reach or interact with covered parts of the window.

2. Use of Visibility

The specific role of each attribute cannot be clearly understood through the above explanation, so let me introduce the role of each attribute in detail one by one.
For the convenience of display, I will create two activities: InputActivity1 and InputActivity2, and set their properties for operation.

1.stateUnchanged

Preserves whatever state the soft keyboard was last in when the Activity comes to the foreground, whether visible or hidden.
How to understand this sentence? We set the windowSoftInputMode of both Activities to stateUnchanged. Then look at an example of operation below:
insert image description here

Let me explain the phenomenon. First, when entering InputActivity1, the soft keyboard is not displayed. Exhale the soft keyboard on InputActivity1, and then jump to InputActivity2. At this time, you will find that the soft keyboard will also be displayed on InputActivity2. Continue to see the following operation examples:
insert image description here

The soft keyboard is not called out on InputActivity1, and then jumps to InputActivity2. At this time, it will be found that the soft keyboard is not displayed on InputActivity2.
Through these two examples, we conclude that stateUnchanged will not change the display state of the soft keyboard. If the soft keyboard was displayed before, it will also be displayed in other activities, and vice versa.

The examples just now are all advancing to another Activity, what if it is returning to the previous Activity?
insert image description here

First of all, if InputActivity1 does not display the soft keyboard, jump to InputActivity2, manually wake up the soft keyboard in InputActivity2, and then return to InputActivity1. It can be found that the soft keyboard is also displayed at this time, so it can be seen that stateUnchanged is applicable whether it is forward or backward .

2.stateHidden

When the user selects an activity—that is, when the user actually navigates forward into the activity, rather than returning from leaving another activity—hide the soft keyboard.
Similarly, we set the windowSoftInputMode of both Activities to stateHidden. Then look at the following operation example:
insert image description here
firstly, the soft keyboard is not displayed when entering InputActivity1, and then jumps to InputActivity2 after manually arousing the soft keyboard. The soft keyboard is hidden on InputActivity2, which means that stateHidden works. When the user navigates forward to the Activity, the soft keyboard will be hidden .
Then invoke the soft keyboard on InputActivity2 and return to InputActivity1. It can be found that the InputActivity1 soft keyboard is displayed at this time, so it can be seen that stateUnchanged takes effect only when it is moving forward.

3.stateAlwaysHidden

Always hide the soft keyboard when the Activity's main window has input focus.
Although the soft keyboard is also hidden, there are fewer qualifiers for stateAlwaysHidden. As mentioned earlier, stateHidden must navigate forward to the Activity to take effect, but stateAlwaysHidden does not have this restriction, and it takes effect whether it is forward or backward. Let's take a look at the actual operation. Similarly, we set the windowSoftInputMode of the two activities to stateAlwaysHidden:
insert image description here
the same operation as the stateHidden above, but when the soft keyboard is aroused on InputActivity2 and returned to InputActivity1, it can be found that the soft keyboard of InputActivity1 is hidden at this time, so it can be seen that stateAlwaysHidden is applicable whether it is forward or backward.

4.stateVisible

When the user selects an activity—that is, when the user actually navigates forward into the activity, rather than returning from leaving another activity—display the soft keyboard.
Visible and Hidden have the same meaning. In order to see its function more clearly, we set InputActivity1 to stateVisible and InputActivity2 to stateHidden this time, and then look at the following operation example: when entering InputActivity1, the soft keyboard is automatically displayed. When entering InputActivity2, it is hidden because of the set stateHidden. When returning to InputActivity1 again It is not displayed, it can be seen that stateVisible only takes effect when moving
insert image description here
forward .

There is a point to note about the two properties of Visible:
in versions above Android 9.0, that is, API28, the two properties displayed will be invalid, which is explained in the source code comments:

        /**
         * Visibility state for {@link #softInputMode}: please show the soft
         * input area when normally appropriate (when the user is navigating
         * forward to your window).
         *
         * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
         * is ignored unless there is a focused view that returns {@code true} from
         * {@link View#isInEditMode()} when the window is focused.</p>
         */
        public static final int SOFT_INPUT_STATE_VISIBLE = 4;

        /**
         * Visibility state for {@link #softInputMode}: please always make the
         * soft input area visible when this window receives input focus.
         *
         * <p>Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag
         * is ignored unless there is a focused view that returns {@code true} from
         * {@link View#isInEditMode()} when the window is focused.</p>
         */
        public static final int SOFT_INPUT_STATE_ALWAYS_VISIBLE = 5;

Applications that target {@link android.os.Build.VERSION_CODES#P} and later, this flag is ignored unless there is a focused view that returns {@code true} from {@link View#isInEditMode()} when the window is focused.

This article introduces the cause of failure in detail: https://blog.csdn.net/weimingjue/article/details/99738271
Simply put, before Android 9.0, an Activity will automatically get the focus after it starts, but it won’t happen afterwards, which will cause the display of the soft keyboard to fail. The solution is to manually get the focus view.requestFocus() on the control that needs input after the Activity starts

5.stateAlwaysVisible

Always show the soft keyboard when the Activity's main window has input focus.
Not much to say about this, just look at the operation example:
insert image description here
Compared with stateVisible, the soft keyboard is automatically displayed when returning to InputActivity1. It can be seen that stateAlwaysVisible is applicable whether it is forward or backward.

6.stateUnspecified

The state of the soft keyboard (hidden or visible) is not specified. It will be up to the system to choose the appropriate state, or rely on the setting in the theme.
This is the default setting for soft keyboard behavior.

I won’t go into details about this setting without specifying a specific method (it’s quite complicated), as long as you can master the other settings above, it should be able to meet your daily development needs.

3. Display method

Simple analysis first:
We know that the soft keyboard is actually a Dialog. When the keyboard pops up, you can actually see two windows: 1 is the Window of the Activity, and 2 is the Window of the Dialog. The crux of the problem is that Dialog's Window display covers part of the Activity's Window area. In order to make the EditText visible, the Activity's layout is pushed up. It is guessed that the Window property has a parameter to control whether it is pushed up. Really, this parameter is WindowManager.LayoutParams.softInputMode.

1.adjustResize

Always resize the activity's main window to make room for the on-screen soft keyboard.
adjustResize actually adds padding to the root layout, and the value of padding is the height of the soft keyboard. You can add padding directly to the root layout, the effect is the same.

We use the following layout code for testing:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/myviewgroup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv"
        android:src="@drawable/test"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:layout_width="match_parent"
        android:layout_height="300dp">
    </ImageView>

    <EditText
        android:hint="输入框2"
        android:id="@+id/et2"
        android:layout_gravity="bottom"
        android:layout_marginTop="200dp"
        android:layout_width="100dp"
        android:layout_height="40dp">
    </EditText>

</LinearLayout>

Set the Activity to adjustResize, and the effect after running is as follows:
insert image description here
You can see that the layout has not changed, and the input box is hidden. This is because the length of the controls in the layout is fixed , and there is no effect even if padding is added.
Next, we modify the layout and set the height of the Imageview to layout_weight=1 to fill up the remaining screen.
The modified content is as follows:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/myviewgroup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv"
        android:src="@drawable/test"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:layout_weight="1"
        android:layout_width="match_parent"
        android:scaleType="fitXY"
        android:layout_height="0dp">
    </ImageView>

    <EditText
        android:hint="输入框2"
        android:id="@+id/et2"
        android:layout_width="100dp"
        android:layout_height="40dp">
    </EditText>

</LinearLayout>

insert image description here
It can be seen that the layout content that is not a fixed length is pushed up and the height is compressed.

2.adjustPan

Instead of adjusting the size of the main window of the Activity to make room for the soft keyboard, the content of the window is automatically panned so that the current focus is never covered by the keyboard, so that the user can always see the content they input. This is generally less desirable than resizing, since the user may need to close the soft keyboard to reach or interact with covered parts of the window.
The adjustPan is actually scrolling up the layout as a whole, no matter what kind of layout here is an effect, but it should be noted that the scrolling layout is determined according to the position of the current focus

Test with the same layout as adjustResize

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/myviewgroup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="fitXY"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:src="@drawable/test"></ImageView>

    <EditText
        android:id="@+id/et2"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:layout_marginTop="100dp"
        android:hint="输入框2"></EditText>
</LinearLayout>

insert image description here

3.adjustUnspecified

Does not specify whether the activity's main window resizes to make room for the soft keyboard, or whether the window contents pan to reveal the current focus on the screen. The system automatically selects one of these modes based on whether the contents of the window have any layout views that can scroll their contents. If such a view exists, the window will resize, provided that all of the window's contents can be seen within a smaller area by scrolling. This is the default setting for the behavior of the main window.

adjustUnspecified is actually to choose one of adjustResize and adjustPan. If there is a scrollable layout in the layout content, choose adjustResize. If not, choose adjustPan. So what kind of content is scrollable content? In fact, it is mainly defined by the attribute isScrollContainer . When the attribute isScrollContainer of the layout is set to true, it means that the layout can be scrolled.

The RecyclerView and ScrollView we usually use are all scrollable content, and they set this property when they initialized

    public RecyclerView(Context context, @android.annotation.Nullable AttributeSet attrs, int defStyle) {
    
    
        ...
        setScrollContainer(true);
        ...
    }

For ordinary View, if you want to set this property, there are two ways:

  1. In the code: View.setScrollContainer(true)
  2. xml里: android:isScrollContainer=“true”

Also tested with the layout above

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/myviewgroup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="fitXY"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:src="@drawable/test"></ImageView>

    <EditText
        android:id="@+id/et2"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:layout_marginTop="100dp"
        android:hint="输入框2"></EditText>
</LinearLayout>

insert image description here
It can be seen that since there is no sliding layout, adjustPan is selected here to push the entire layout up. Next, we add the isScrollContainer attribute to the ImageView:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/myviewgroup"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_gravity="center_vertical"
    android:background="@color/white"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:id="@+id/iv"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:scaleType="fitXY"
        android:isScrollContainer="true"
        android:layout_marginTop="20dp"
        android:layout_marginBottom="20dp"
        android:src="@drawable/test"></ImageView>

    <EditText
        android:id="@+id/et2"
        android:layout_width="100dp"
        android:layout_height="40dp"
        android:layout_marginTop="100dp"
        android:hint="输入框2"></EditText>
</LinearLayout>

insert image description here
Here I chose adjustResize.

4.adjustNothing

Do nothing.

Summarize

The above is the analysis of the soft keyboard pop-up, close, whether to display, soft keyboard height, soft keyboard mode and other effects.
If you want to understand the realization principle of the above effects, you can read the next article, the use and principle of the Android soft keyboard windowSoftInputMode (principle)

Guess you like

Origin blog.csdn.net/shanshui911587154/article/details/124462145