输入法
android:windowSoftInputMode 属性(输入法软键盘的那点事)
(1)AndroidManifest.xml文件中界面对应的`<activity>`里加入
android:windowSoftInputMode="adjustPan" 键盘就会覆盖屏幕
android:windowSoftInputMode="stateVisible|adjustResize" 屏幕整体上移
(2)windowSoftInputMode属性设置值说明。
<activity android:windowSoftInputMode=["stateUnspecified",
"stateUnchanged", "stateHidden",
"stateAlwaysHidden", "stateVisible",
"stateAlwaysVisible", "adjustUnspecified",
"adjustResize", "adjustPan"] …… >
</activity>
attributes:
android:windowSoftInputMode
活动的主窗口如何与包含屏幕上的软键盘窗口交互。这个属性的设置将会影响两件事情 :
1> 软键盘的状态——是否它是隐藏或显示——当活动 (Activity)成为用户关注的焦点。
2> 活动的主窗口调整——是否减少活动主窗口大小以便腾出空间放软键盘或是否当活动窗口的部分被软键盘覆盖时它的内容的当前焦点是可见的。
它的设置必须是下面列表中的一个值,或一个 ”state…”值加一个 ”adjust…”值的组合。在任一组设置多个值——多个 ”state…”values,例如& mdash有未定义的结果。各个值之间用 |分开。例如 : <activity android:windowSoftInputMode="stateVisible|adjustResize" . . . >
在这设置的值 (除 "stateUnspecified"和 "adjustUnspecified"以外 )将覆盖在主题中设置的值
值
描述
"stateUnspecified"
软键盘的状态 (是否它是隐藏或可见 )没有被指定。系统将选择一个合适的状态或依赖于主题的设置。
这个是为了软件盘行为默认的设置。
"stateUnchanged"
软键盘被保持无论它上次是什么状态,是否可见或隐藏,当主窗口出现在前面时。
"stateHidden"
当用户选择该 Activity时,软键盘被隐藏——也就是,当用户确定导航到该 Activity时,而不是返回到它由于离开另一个 Activity。
"stateAlwaysHidden"
软键盘总是被隐藏的,当该 Activity主窗口获取焦点时。
"stateVisible"
软键盘是可见的,当那个是正常合适的时 (当用户导航到 Activity主窗口时 )。
"stateAlwaysVisible"
当用户选择这个 Activity时,软键盘是可见的——也就是,也就是,当用户确定导航到该 Activity时,而不是返回到它由于离开另一个Activity。
"adjustUnspecified"
它不被指定是否该 Activity主 窗口调整大小以便留出软键盘的空间,或是否窗口上的内容得到屏幕上当前的焦点是可见的。系统将自动选择这些模式中一种主要依赖于是否窗口的内容有任何布局 视图能够滚动他们的内容。如果有这样的一个视图,这个窗口将调整大小,这样的假设可以使滚动窗口的内容在一个较小的区域中可见的。这个是主窗口默认的行为 设置。
"adjustResize"
该 Activity主窗口总是被调整屏幕的大小以便留出软键盘的空间
"adjustPan"
该 Activity主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望比调整大小,因为用户可能关闭软键盘以便获得与被覆盖内容的交互操作。
原文说的已经很清楚,但是通过自己动手实践才更加形象。以此在原文的基础上加了一些自己实践过的备注,方便以后再次使用。
一、windowSoftInputMode 是什么?
android:windowSoftInputMode 属性用于指示在安卓界面中出现的软键盘如何与界面互相配合显示以达到良好的用户体验。
二、windowSoftInputMode 如何使用?
该属性可以在 工程->Manifest.xml的Application->Activity节点中指定,表示对该activity的设定,如:
<activity
android:name="com.navigator.LoginActivity"
android:label="@string/title_activity_login"
android:windowSoftInputMode="adjustResize|stateHidden" >
</activity>
三、windowSoftInputMode属性详解: 这个属性的设置将会影响两件事情 : 1、软键盘的显示状态:通过"state..."属性设置。当Activity成为焦点时(导航到该activity时),软键盘是显示还是隐藏。 2、活动窗口如何调整:通过"adjust..."属性设置。弹出软键盘时,是否减少活动主窗口大小以便腾出空间放软键盘,或,是否当活动窗口的部分被软键盘覆盖时它的内容的当前焦点是可见的。
windowSoftInputMode 属性一个"state…"或一个"adjust..."或这二者的组合。各个值之间用 |分开,如第二部分所示。
windowSoftInputMode 属性列表:
值 描述 我的备注
state stateUnspecified 软键盘的状态(是否它是隐藏或可见)没有被指定。系统将选择一个合适的状态或依赖于主题的设置。 这个是为了软件盘行为默认的设置。 跟随系统设置,也就是默认 stateUnchanged 软键盘被保持无论它上次是什么状态,是否可见或隐藏,当主窗口出现在前面时。 stateHidden 当用户选择该Activity时,软键盘被隐藏——也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。 用户设置焦点时,弹出软键盘: 第一次导航到该activity时,即使一个EditText默认获得焦点(光标闪烁),软键盘也不弹出;直到用户点击输入框时才弹出。这是目前app常用的效果 stateAlwaysHidden 软键盘总是被隐藏的,当该Activity主窗口获取焦点时。 总是,隐藏软键盘 stateVisible 软键盘是可见的,当那个是正常合适的时(当用户导航到Activity主窗口时)。 有输入焦点时,弹出软键盘 stateAlwaysVisible 当用户选择这个Activity时,软键盘是可见的——也就是,也就是,当用户确定导航到该Activity时,而不是返回到它由于离开另一个Activity。 总是,弹出软键盘 adjust adjustUnspecified 它不被指定是否该Activity主窗口调整大小以便留出软键盘的空间,或是否窗口上的内容得到屏幕上当前的焦点是可见的。系统将自动选择这些模式中一种主要依赖于是否窗口的内容有任何布局视图能够滚动他们的内容。如果有这样的一个视图,这个窗口将调整大小,这样的假设可以使滚动窗口的内容在一个较小的区域中可见的。这个是主窗口默认的行为设置。 跟随系统设置,也就是默认 adjustPan 该Activity主窗口并不调整屏幕的大小以便留出软键盘的空间。相反,当前窗口的内容将自动移动以便当前焦点从不被键盘覆盖和用户能总是看到输入内容的部分。这个通常是不期望比调整大小,因为用户可能关闭软键盘以便获得与被覆盖内容的交互操作。 当EditText获得输入焦点,若弹出的软键盘将遮挡该EditText,则自动移动界面使得该EditText不被遮挡;若弹出的软键盘不会遮挡【该EditText】,则没有事情发生。(只关注该EditText死活,不管其他) (比如,底部的EditText获得焦点弹出软键盘,会使得界面上移,EditText处于软键盘上方) adjustResize 该Activity主窗口总是被调整屏幕的大小以便留出软键盘的空间 始终调整整个界面,使得“更友好地”输入。从效果上来看,这是目前app常用的效果。
四、关于软键盘出现把原来底部布局给顶上去的原因与解决方法
这个问题看图便知:
这个问题来自adjust参数的设定,与state无关
根据我的实践推测,在不人为指定windowSoftInputMode 的adjust时,该属性默认为adjustUnspecified,因此会使用系统默认的行为,据我观察,系统默认行为是
adjustResize。根据第三部分我对adjustResize的备注,系统为了更友好地显示界面,将底部按钮调整到了软键盘上方。
这在一些情况确实是友好的,比如微信聊天界面,底部的输入框会被软键盘顶上去(这里就不放图啦)
解决办法
但如果想不被顶上去,老老实实呆在底部,除了从界面布局入手(定死location等),将windowSoftInputMode 指定为adjustPan即可。
五、使用程序代码关闭输入法
如,输入用户名密码后,点击登录按钮进行登录操作,这时候隐藏输入法是一个较好的用户体验。
相关代码网上有,这里只记录一段用到的代码:
/* 关闭输入法 */
public static void hideSoftInput(Activity activity) {
InputMethodManager inputMethodManager = (InputMethodManager) activity
.getSystemService(Context.INPUT_METHOD_SERVICE);
if (inputMethodManager != null) {
// 获得当前活动组件,一般是输入框
View v = activity.getCurrentFocus();
if (v != null) {
inputMethodManager.hideSoftInputFromWindow(v.getWindowToken(),
InputMethodManager.HIDE_NOT_ALWAYS);
// 接受软键盘输入的编辑文本或其它视图
// inputMethodManager.showSoftInput(v,
// InputMethodManager.SHOW_FORCED);
}
}
}
参数activity是当前活动。
https://blog.csdn.net/wkw1125/article/details/48414163
Android-状态栏透明导致android:windowSoftInputMode属性失效
今天UI给的新设计稿,要求状态栏透明。透明化的状态看效果还挺不错。大概是这个样子(请忽略这张难看的背景,只是一个Demo):
这里写图片描述 方法呢,也很简单,onCreate 里一行代码:
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
1 2 同时。因为输入框都在底部,最下面还有一个按钮,所以为了用户体验,需要保证的是输入法弹出后,三个控件都向上移。就是这个效果: 这里写图片描述
这个一般来说很简单的,只要这样在AndroidManifest中的Activity下加一条这个属性就好了:
<activity
android:name=".activity.LoginActivity"
android:label="@string/title_activity_message"
android:windowSoftInputMode="adjustResize|stateHidden">
</activity>
1 2 3 4 5 6 但闹心的问题来了。在没有修改状态栏之前,是没有问题的。可是设置标题栏为透明后,就变成这样了:
这里写图片描述 背景太难看,被我去掉了。现在输入法盖住了下面的控件,就连当前输入框都盖了一点。
我头都大了,这是怎么了?然后开始排查: 1.难道是和主题冲突了?屏蔽主题。 无效 2.之前用的线性布局,改成相对布局了。这个的问题? 无效 3.android:windowSoftInputMode=”adjustResize|stateHidden”之前在配置文件里写的,换在java代码里。无效 4.剩下新添加的只有 状态栏透明 这条代码了。暂时注释掉,好吧……View跟着输入法上移了。现在可以确定。状态栏透明和android:windowSoftInputMode冲突了。但怎么解决呢? 5.难道是设置完windowSoftInputMode以后状态栏透明的操作覆盖这条属性?换一下他们的位置: (还是不行!!!)
//透明状态栏 getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); //根据输入法调整View移动 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN| WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE); 1 2 3 6.好吧,既然状态栏透明冲突了,我把状态去掉行不行? 结论是无效!
我脑袋都大了……百度!google!终于找到解决办法了。重写根布局!!
需要注意的是,继承布局后重写的是fitSystemWindows方法,但是这个方法已经过期了,如果你的应用最低支持的是 API 20以上,可以重写这个方法:onApplyWindowInsets
/**
- 此Layout是为解决 当设定状态栏为透明后,android:windowSoftInputMode="adjustResize"
- 失效,导致输入法覆盖View的Bug
- zhaoxuan.li
- 2015/10/21. */ public class LoginLayout extends RelativeLayout {
private int[] mInsets = new int[4];
public LoginLayout(Context context) { super(context); }
public LoginLayout(Context context, AttributeSet attrs) { super(context, attrs); }
public LoginLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); }
public final int[] getInsets() { return mInsets; }
/**
此方法以过期,当应用最低API支持为20后,可以重写以下方法
@Override public final WindowInsets onApplyWindowInsets(WindowInsets insets) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mInsets[0] = insets.getSystemWindowInsetLeft(); mInsets[1] = insets.getSystemWindowInsetTop(); mInsets[2] = insets.getSystemWindowInsetRight(); return super.onApplyWindowInsets(insets.replaceSystemWindowInsets(0, 0, 0, insets.getSystemWindowInsetBottom())); } else { return insets; } }
未测试…… */ @Override protected final boolean fitSystemWindows(Rect insets) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) { mInsets[0] = insets.left; mInsets[1] = insets.top; mInsets[2] = insets.right; return super.fitSystemWindows(insets); } else { return super.fitSystemWindows(insets); } } }
然后用这个自定义布局替换你的根布局,同时记得设置这条属性:
android:fitsSystemWindows="true" 1 2 OK,现在问题就解决了。
https://blog.csdn.net/u010255127/article/details/49308775