转载自 Vander丶
修正
1.修正了flagNoFullscreen和flagNoExtractUi的说明,以及区别。
背景
1.Android软键盘这块从我入职到现在,是一个一直纠缠我的问题。
2.从布局挤压,到EditText显示不全,在到弹出时卡顿,在Android软键盘面前我无数次跌倒。
3.因为网上大多数的知识点比较分散而且很杂,所以本篇做一个整合篇。
4.Android软键盘这块知识点比较密集,了解过一次之后,差不多什么情况都可以找到原因了。
5.感谢Android软键盘的问题,从我入职陪伴我到现在,让我一个一个不停的解决。
前言
本文将从以下几个方面进行介绍:
(1)InputMethodService的源码解析,从源码解读中告诉你为什么软键盘弹出的是一个Dialog
(2)Android软键盘显示时,设置windowSoftInputMode的作用
(3)EditText设置imeOptions属性对软键盘的影响
(4)软键盘上面的按键监听
(5)横屏状态下,不希望软键盘显示全屏怎么处理
(6)控制软键盘的弹出和关闭的方法
(7)EditText在软键盘弹出的时候显示不全,怎么获取软键盘弹出和关闭的监听
(8)软键盘弹出的时候,造成页面卡顿,这时候如何发现问题并解决问题
(9)Android键盘面板冲突,布局闪动的解决方法
Android软键盘的显示原理
软键盘其实是一个Dialog
InputMethodService为我们的输入法创建了一个Dialog,并且对某些参数进行了设置,使之能够在底部或者全屏显示。当我们点击输入框时,系统会对当前的主窗口进行调整,以便留出相应的空间来显示该Dialog在底部,或者全屏。
其实这段话我们经常在各种软键盘博客所看到,但是大家并不知道Android是怎么为我们创建的这个Dialog,所以我先带大家来看下软键盘生成这块的源码,了解软键盘的生成流程。
InputMethodService的源码解析
因为InputMethodService属于服务,接下来我们先看一下服务的入口onCreate()方法:
@Override
public void onCreate() {
//设置主题与xml里面设置theme是一样的道理
mTheme = Resources.selectSystemTheme(mTheme,
getApplicationInfo().targetSdkVersion,
android.R.style.Theme_InputMethod,
android.R.style.Theme_Holo_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod,
android.R.style.Theme_DeviceDefault_InputMethod);
super.setTheme(mTheme);
//创建InputMethodMananger
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mSettingsObserver = SettingsObserver.createAndRegister(this);
mShouldClearInsetOfPreviousIme = (mImm.getInputMethodWindowVisibleHeight() > 0);
mInflater = (LayoutInflater)getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
/**
* 这里注意一下,首先这里的命名属于Window,然后我们发现了Gravity.BOTTOM,就更加确定了这个就是
* 软键盘所创建的Dialog对象
*/
mWindow = new SoftInputWindow(this, "InputMethod", mTheme, null, null, mDispatcherState,
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
if (mHardwareAccelerated) {
mWindow.getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
}
initViews();
mWindow.getWindow().setLayout(MATCH_PARENT, WRAP_CONTENT);
}
通过上面的分析,我们怀疑这里的SoftInputWindow是软键盘弹出创建的Dialog对象,下面我们看下SoftInputWindow的源码。
public class SoftInputWindow extends Dialog{
....
}
看到这里大家就能明白了,为什么说软键盘就是一个Dialog。而且这里通过设置Gravity.BOTTOM来控制当前Dialog在Window中的位置。
软键盘的显示调整(windowSoftInputMode)
在Android中,可以通过给Activity设置windowSoftInputMode这个属性来控制软键盘与Activity的主窗口的交互方式。
Activity 的主窗口与包含屏幕软键盘的窗口的交互方式,该属性的设置影响两个方面:
当Activity成为用户注意的焦点时软键盘的状态 - 隐藏还是可见。
对Activity主窗口所做的调整 - 意思是是否将其尺寸调小为软键盘腾出空间,或者当窗口部分被软键盘遮挡时是否平移其内容以使当前焦点可见。
该设置必须是下面所列的值之一,或者是一个“state…”值加上一个“adjust…”值的组合,在任一组中设置多个值(例如,多个“state…”值)都会产生未定义结果。各值之间使用垂直条 (|) 分隔
(1)控制软键盘显示还是隐藏
1
stateUnspecified-不指定软键盘的状态(隐藏还是可见) 将由系统选择合适的状态,或依赖主题中的设置,这是对软键盘行为的默认设置
stateUnchanged-保留状态 当 Activity 转至前台时保留软键盘最后所处的任何状态,无论是可见还是隐藏
stateHidden-隐藏软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时隐藏软键盘
stateAlwaysHidden-始终隐藏软键盘 当 Activity 的主窗口有输入焦点时始终隐藏软键盘
stateVisible-显示软键盘 在正常的适宜情况下(当用户向前导航到 Activity 的主窗口时)显示软键盘
stateAlwaysVisible-显示软键盘 当用户确实是向前导航到 Activity,而不是因离开另一Activity 而返回时.
(2)在软键盘弹出时,是否需要Activity对此进行调整
1
adjustUnspecified 主窗口的默认行为,不指定 Activity 的主窗口是否调整尺寸以为软键盘腾出空间,或者窗口内容是否进行平移以在屏幕上显露当前焦点。 系统会根据窗口的内容是否存在任何可滚动其内容的布局视图来自动选择其中一种模式。 如果存在这样的视图,窗口将进行尺寸调整,前提是可通过滚动在较小区域内看到窗口的所有内容。
adjustResize 始终调整 Activity 主窗口的尺寸来为屏幕上的软键盘腾出空间。
adjustPan 不调整 Activity 主窗口的尺寸来为软键盘腾出空间, 而是自动平移窗口的内容,使当前焦点永远不被键盘遮盖,让用户始终都能看到其输入的内容。 这通常不如尺寸调整可取,因为用户可能需要关闭软键盘以到达被遮盖的窗口部分或与这些部分进行交互。
adjustNoting 软键盘弹出时,主窗口Activity不会做出任何响应。
windowSoftInputMode 应用场景
下面将通过例子来介绍adjustNoting、adjustUnspecified、adjustResize、adjustPan在软键盘弹出的区别:
adjustUnspecified : 当软键盘弹出时,系统自动指定窗口的调整模式,根据不同的情况会选择adjustResize或者adjustPan的一种。
adjustPan : 当软键盘弹出时,会将主窗口的平移(translateY),来适应软键盘的显示。
adjustResize : 当软键盘弹出时,会让布局重新绘制,这种一般适应于带有滑动性质的控制,让其向下滚动,然后适应软键盘的显示。
adjustNoting: 软键盘弹出时,主窗口不会做出任何反应。
非滚动布局xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容2" />
..........<中间包含无数的EditText>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容12" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容13" />
</LinearLayout>
点击最下面的EditText12
(1)设置windowSoftInputMode为adjustNoting
从上图发现,当点击EditText12时,弹出软键盘将主窗口下半部分给遮盖,并且主窗口没有做出任何反应。
(2)设置windowSoftInputMode为adjustPan
当设置其属性为adjustPan时,当软键盘弹出时,主窗口布局会上移至直到显示EditText12。
(3)设置windowSoftInputMode为adjustUnspecified
当设置其属性为默认属性adjustUnspecified时,发现当点击EditText12时,主窗口上移来保持EditText12在软键盘之上,这时adjustUnspecified的表现形式与adjustPan相同,所以在无滑动的控件上,默认的指定形式为adjustPan。
(4)设置windowSoftInputMode为adjustResize
设置其属性为adjustResize时,发现软键盘弹出的状态与adjustNoting表现一致,当设置adjustResize时,布局会为了软键盘弹出而重新绘制给软键盘留出空间,而由于控件无法滑动,所以表现的形式与adjustNoting一致。
滚动布局xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容1" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容2" />
..........<中间有很多了EditText>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容12" />
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入您要输入的内容13" />
</LinearLayout>
</ScrollView>
</LinearLayout>
https://blog.csdn.net/harryweasley/article/details/50266749 弹出软键盘后输入框上移,背景不变。