Android keyboard blocks the input box solution

Reprinted from: http://www.10tiao.com/html/227/201705/2650239474/1.html

In development, it is often encountered that the keyboard blocks the input box, such as the login interface or registration interface, the pop-up soft keyboard blocks the login or registration button, and the user must put the soft keyboard away before clicking the corresponding button. Such a user Very bad experience. Like WeChat, the login button is directly placed on the input box, but in many cases, this often fails to meet the needs. At the same time, if there are too many input boxes, when you click the input, the current input box is not blocked, but the input box below the current input box cannot get the focus, you must first put the keyboard away, and then get the focus of the input box below, so The user experience is also very bad, so what can be done?

What is the difference between adjustResize and adjustPan of the system, what should be paid attention to when using them, what are the system requirements and shielded ends?

The following is a summary of several methods commonly used in development:

Method 1: windowSoftInputMode: adjustResize and adjustPan

Main implementation method: Add android:windowSoftInputMode=”adjustPan” or android:windowSoftInputMode=”adjustResize” attribute to the Activity corresponding to AndroidManifest.xml

The official explanation for the difference between these two properties is: 

The purpose of these two properties is to adjust the interface so that the keyboard does not block the input box. Here, I have made a comprehensive summary of the usage scenarios, advantages and disadvantages, and precautions of these two properties. I wonder if you have noticed them when you use them.

  • AdjustResize failure situation : The activity sets the full-screen attribute to refer to Theme.Light.NotittleBar.Fullscreen or sets the android:windowTranslucentStatus attribute in the theme corresponding to the activity. The setting method is: android:windowTranslucentStatus=true, then if the corresponding page contains an input box , it will cause the soft keyboard to pop up when the input box is clicked, and then the keyboard will cover the input box, making the input box invisible.

  • fitsSystemWindows=”true”, only the initial view works : if the fitSystemWindows=”true” is not set in the outermost control in the layout, then the height of the set control will be one more height of the status bar. If there are multiple view settings, because the first view has consumed the INSECT, the other view settings will also be ignored by the system.

Suppose the original interface is a LinearLayout containing several EditTexts, as shown in the following figure, when using the two properties respectively:

1、adjustPan

The entire interface is moved upward to expose the input box, it will not change the layout of the interface; the overall available height of the interface is still the height of the screen, which can be seen from the screenshot below. For example, if you click on the input box 6, the input box will be pushed to the top of the keyboard, But the input box 1 is pushed out. If the interface contains a title bar, it will also be pushed out.

2、adjustResize

The height of the interface needs to be variable, or the size of the main Activity window can be adjusted. If it cannot be adjusted, it will not work.

For example: there is only one LinearLayout in the xml layout of the Activity that contains several EditTexts, set the android:windowSoftInputMode=”adjustResize” property in the AndroidMainfest.xml of the Activity, click the input box 6, and find that the soft keyboard blocks the input box 6, and it is not adjusted, as follows As shown in the figure:

But using these two properties, we can summarize the following:

1).  Using adjustPan, if there are many items to be input, click the input box, the current input item will be pushed to the top of the soft keyboard, but if there are input items under the current input box, you need to put away the keyboard first, then click The corresponding input items can only be entered. This operation is too cumbersome and not good for user experience;

2).  The use of adjustResize requires that the content of the window that can be displayed on the interface itself can be adjusted. If not, it will not work;

Method 2: Wrap ScrollView in the outermost layout of the interface

1. Use only ScrollView

In the xml layout of the corresponding interface, add a ScrollView to the outermost layer, and do not set any android:windowSoftInputMode attribute in AndroidMainfest.xml. Click the input box at this time, and the input box will not be blocked by the soft keyboard. Even if there is an input box below the current input box, when the keyboard is displayed, you can also slide the interface up and down to input, instead of hiding the keyboard first, click the input box below, and then display the keyboard input.

We can view the layout height actually occupied by the interface according to the Inspect Layout tool of Android Studio. The tool is:

With this tool, we see:

The actual height of the interface = screen height - status bar height - soft keyboard height

The blue box in the interface is the height used by the real interface:

2、ScrollView + adjustPan

We then set the windowSoftInputMode property to adjustPan in the AndroidMainfest.xml of the class:

It is found that the current input box will not be blocked, but when there are many input boxes, when a keyboard is displayed, the interface slides up and down, but only part of it can be slid, and if the input box is at the bottom of the interface, click the input box, the title bar will also be blocked. Top out, as shown below: 

We use the Inspect Layout tool to view the available height of this set layout. As can be seen from the figure below, the available height of the layout is the height of the screen at this time, and sliding up and down is only the height of this screen. The input boxes below input box 9 cannot slide out. Swipe up, you can only swipe to input box 1. 

3、ScrollView+adjustResize

We said earlier that the use of adjustResize must be variable in height of the interface layout, such as a ScrollView in the outermost layer or a retractable interface, it will work. Here, set the windowSoftInputMode property to adjustResize in the AndroidMainfest.xml of this class

It is found that the effect is similar to 1 without setting any windowSoftInputMode property, and its height is also: screen height - status bar height - soft keyboard height

Let's take a look at the default property value stateUnspecified of windowSoftInputMode:

It can be seen that the system will select the appropriate state, that is, when the outermost layer of the interface contains a layer of ScrollView, setting the default property value stateUnspecified is actually the adjustResize property.

However, the following two aspects cannot meet the needs:

1). When the Activity is set to fullscreen fullscreen mode or using the immersive status bar, the outermost layer of the interface wraps ScrollView. When the input box exceeds one screen, the input box below the current input box cannot slide up and down to input, the situation is similar For ScrollView+adjustPan, only the sliding part can be seen. You can also see through Inspect Layout that the available height of the interface is the height of the entire screen, and the height will not be adjusted. Even setting adjustResize doesn't work.

2). If it is similar to the registration interface or the login interface, the keyboard will block the login button below the input box.

Immersive status bar

Since android system 4.4 (API>=19), immersive status bar has been supported. When using System windows (system window) to display some properties and operation areas of the system, such as the top status and the bottom virtual navigation bar without physical buttons .

android:fitsSystemWindows="true" will make the layout space on the screen below the status bar and above the navigation bar.

Method 3: When the keyboard pops up, let the interface move up as a whole; when the keyboard is folded, let the interface move down as a whole

使用场景:针对界面全屏或是沉浸式状态栏,输入框不会被键盘遮挡。主要用于一些登录界面,或是需要把界面整体都顶上去的场景。

1、主要实现步骤

(1). 获取Activity布局xml的最外层控件,如xml文件如下:

先获取到最外层控件:

RelativeLayout main = (RelativeLayout) findViewById(R.id.main);

(2). 获取到最后一个控件,如上面的xml文件,最后一个控件是Button:

Button login_btn = (Button) findViewById(R.id.login_btn);

(3). 给最外层控件和最后一个控件添加监听事件:

2、实现原理

此方法通过监听 Activity 最外层布局控件来检测软键盘是否弹出,然后去手动调用控件的 scrollTo方法 达到调整布局目的。

方法四:监听Activity顶层View,判断软键盘是否弹起,对界面重新绘制

此方法的实现来自android中提出的issue 5497

https://code.google.com/p/android/issues/detail?id=5497

使用场景:针对界面全屏或是沉浸式状态栏,界面包含比较多输入框,界面即使包裹了一层 ScrollView,在键盘显示时,当前输入框下面的输入不能通过上下滑动界面来输入。

一、实现步骤

1、把 SoftHideKeyBoardUtil类 复制到项目中; 

2、在需要使用的Activity的onCreate方法中添加 SoftHideKeyBoardUtil.assistActivity(this) 即可。

二、实现原理

SoftHideKeyBoardUtil类 具体代码如下:

它的实现原理主要是:

(1). 找到 Activity 的最外层布局控件,我们知道所有的 Activity 都是 DecorView,它就是一个 FrameLayout控件,该控件id是系统写死叫 R.id.content,就是我们 setContentView 时,把相应的 View 放在此 FrameLayout 控件里

FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);

所以 content.getChildAt(0) 获取到的 mChildOfContent,也就是我们用 setContentView 放进去的 View。

(2). 给我们的 Activity 的xml布局View设置一个 Listener 监听:

View.getViewTreeObserver() 可以获取一个 ViewTreeObserver对象——它是一个观察者,用以监听当前 View树 所发生的变化。这里所注册的 addOnGlobalLayoutListener,就是会在当前的 View树 的全局布局(GlobalLayout)发生变化、或者其中的 View 可视状态有变化时,进行通知回调。『软键盘弹出/隐 』都能监听到。

(3). 获取当前界面可用高度

如下图所示: 

(4). 重设高度, 我们计算出的可用高度,是目前在视觉效果上能看到的界面高度。但当前界面的实际高度是比可用高度要多出一个软键盘的距离的。

通过上面的这种方法,一般布局输入键盘挡住输入框的问题基本都能解决。即使界面全屏或是沉浸式状态栏情况。

总结

下面对上面几种方法进行对比:

方法一:

  • 优点:使用简单,只需在Activity的AndroidMainfest.xml中设置windowSoftInput属性即可。

  • 注意点:adjustResize属性必须要界面大小可以自身改变;

  • 缺点:当输入框比较多时,当前输入框下方的输入框会初键盘挡住,须收起键盘再进入输入;使用adjustPan,输入框较多时,因它是把界面当成一个整体,只会显示一屏的高度,会把ActionBar顶上去。

方法二:

  • 优点:使用简单,只需在Activity的最外层布局包裹一个ScrollView即可。

  • 注意点:不可使用adjustPan属性,否则ScrollView失效;

  • 缺点:对于全屏时,在键盘显示时,无法上下滑动界面达到输入的目的;

方法三:

  • 优点:可以解决全屏时,键盘挡入按钮问题。

  • 缺点:只要有此需求的Activity均需要获取到最外层控件和最后一个控件,监测键盘是否弹出,再调用控件的scrollTo方法对界面整体上移或是下移。代码冗余。

方法四:

  • 优点:可以解决全屏时,键盘挡入输入框问题。只需要写一个全局类,其他有需求的界面直接在onCreate方法里调用此类的全局方法,即可。

  • 缺点:多用了一个类。

综上所述:

1) 当输入框比较少时,界面只有一个输入框时,可以通过方法一设置adjustPan;

2) 如果对于非全屏/非沉浸式状态栏需求,只需要使用方法二即可;

3) 如果全屏全屏/沉浸式状态栏界面只有一个类有键盘挡入输入框需求,可使用方法三;

4) 如果大部分界面均使用全屏或沉浸式状态栏,且有此需求,则选择方法四更恰当。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325526427&siteId=291194637