Welcome to Ray's Blog

Stay Hungry Stay Foolish - Steve Jobs

0%

Android虚拟键盘知识总结


Android:windowSoftInputMode 属性使用详解

1
2
3
4
5
6
7
8
9
10
11
12
<activity
android:windowSoftInputMode=["stateUnspecified"
|"stateUnchanged"
|"stateHidden"
|"stateAlwaysHidden"
|"stateVsible"
|"stateAlwaysVisibe"
|"adjustUnspecified"
|"adjustResize"
|"adjustPan"
]
.../>

attributes:android:windowSoftInputMode : 活动的主窗口如何与屏幕上的软键盘窗口交互;
这个属性的设置将会影响俩件事:

  • 软键盘的状态:当前 Activity 成为焦点的时候,软键盘是隐藏还是显示状态;
  • 浮动的主窗口调整:是否减少活动主窗口大小以便腾出空间放软键盘或者时候当前活动窗口的部分被软键盘覆盖时,它的内容的当前焦点是可见的。
    它的设置必须是下面列表中的一个值,或是一个“state…”值加上一个“adjust…”值的组合。中间使用“|”分隔开
    描述
    “stateUnspecified” 软键盘的状态(显示 or 隐藏)没有被指定。系统将根据默认规则选择一个合适的状态或者依赖于主题的设置。
    “stateUnchanged” 软键盘被保持无论它上次是什么状态,是否可见或者隐藏,当主窗口出现在前面时。
    “stateHidden” 当用户选择该 Activity 时,软键盘被隐藏。
    “stateAlwaysHidden” 软键盘总是被隐藏,当该 Activity 主窗口获得焦点时。
    “stateVisible“ 软键盘是可见的。
    “stateAlwaysVisible” 当用户选择这个 Activity 的时候,软键盘总是可见的。
    “adjustUnspecified” 对窗口的大小设置不做限制,系统自动选择方案执行。
    “adjustResize” 该 Activity 主窗口总是被调整屏幕大小以便留出软键盘的空间。
    “adjustPan” 该 Activity 主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被软键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望调整内容界面大小的,因为用户可以通过关闭软键盘以便获取到被软键盘覆盖的内容的交互操作。

项目难点处理记录

问题描述


如上图所示:红色区域需要保持固定不动,紫色框区域内的 EditText 获得焦点时候,可以改变位置以便软键盘的弹出。

界面 UI 布局 XML 文件

说明:最外层使用 RelativeLayout,内部分 3 部分,上部为 include 布局头部 Bar,中间为一个 Scrollview 包含的图片和

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/code_rl"
style="@style/MatchActivityStyle"
>
<include
android:id="@+id/in_title"
layout="@layout/include_second_titlebar" />
<ScrollView
style="@style/MatchActivityStyle"
android:layout_below="@id/in_title">
<LinearLayout
style="@style/MatchActivityStyle"
android:orientation="vertical">
<ImageView
.../>
<EditText
... />
<Button
... />
</LinearLayout>
</ScrollView>
<LinearLayout
...>
<TextView
.../>
<TextView
.../>
</LinearLayout>
</RelativeLayout>

测试方案 1

AndroidManifest.xml 中设置软键盘的调整和状态方式;

1
2
3
4
5
<activity
android:name=".ui.c_activity.InvitationVerifyCodeActivity"
android:launchMode="singleTop"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan|stateHidden"/>

结果:
正常显示状态:

弹出软键盘后界面 UI 显示:

说明:当软键盘显示的时候:界面被挤压变形。

测试方案 2

将 AndroidManifest.xml 中的 adjustPan 改成 adjustResize;
结果:

说明:头部 Bar 保留了,但是底部的信息却被挤压到键盘上面了。

测试方案 3

adjustResize + CodeRelativeLayout(自定义相对布局);
CodeRelativeLayout.java类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
>import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.RelativeLayout;
public class CodeRelativeLayout extends RelativeLayout {
private static final String TAG = "CodeRelativeLayout==";
public interface OnKeyboardShowListener {
void keyboardShow(int w, int h, int oldw, int oldh);
}
public OnKeyboardShowListener getOnKeyboardShowListener() {
return mOnKeyboardShowListener;
}
public void setOnKeyboardShowListener(OnKeyboardShowListener mOnKeyboardShowListener) {
this.mOnKeyboardShowListener = mOnKeyboardShowListener;
}
private OnKeyboardShowListener mOnKeyboardShowListener;
public CodeRelativeLayout(Context context) {
super(context);
}
public CodeRelativeLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public CodeRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
Log.i(TAG, "onSizeChanged() called with: " + "w = [" + w + "], h = [" + h + "], oldw = [" + oldw + "], oldh = [" + oldh + "]");
if (mOnKeyboardShowListener != null) {
mOnKeyboardShowListener.keyboardShow(w, h, oldw, oldh);
}
super.onSizeChanged(w, h, oldw, oldh);
}
}

说明:
当我们在AndroidManifest.xml中设置android:windowSoftInput:"adjustResize|stateHidden"之后,运行程序时,当软键盘弹出和隐藏时候,会改变当前界面的大小,即会调用ViewGrouponSizeChanged()方法,因此我们可以通过这个方法的调用,使用接口回调的方式获得软键盘的隐藏和显示状态。
结果:

说明:当软键盘显示的时候,动态设置顶部的文本 View 不可见状态,即可保持界面上的完整。这里可以看到中间的 ScrollView 部分被整体上移了,但是基本满足了最初的要求。
上核心代码(我这里是使用的 Fragment):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Bind(R.id.code_rl)
CodeRelativeLayout mCodeRelativeLayout;
@Bind(R.id.tv_qqnumb)
TextView tvQqnumb;
@Bind(R.id.tv_info)
TextView tvInfo; //这里使用ButterKniff 插件,注解方式获取组件实例
//...
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mCodeRelativeLayout.setOnKeyboardShowListener(new CodeRelativeLayout.OnKeyboardShowListener() {
@Override
public void keyboardShow(int w, int h, int oldw, int oldh) {
ViewHelper.setViewsInVisible(h < oldh, llInfo);//封装了一下View的显示和隐藏
}
});
}

不足之处:软键盘显示之后,将输入框遮挡了一部分,UI 显示不友好,需要进一步的研究设置。
填一个坑:这里做view的显示隐藏的时候,不能够使用View.GONE,见下图:
正常显示:

软键盘隐藏之后:

说明:当软键盘隐藏之后,发现设置显示的文本 View 位置发生了变化。应该是设置View.GONE之后的View已经不在原位了,导致显示的时候位置发生了变化。