android全屏/沉浸式状态栏下,各种键盘挡住输入框解决办法[转]

本文主要是介绍android全屏/沉浸式状态栏下,各种键盘挡住输入框解决办法[转],希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转自http://www.voidcn.com/article/p-gcncfbun-bqh.html

*本篇文章已授权微信公众号 guolin_blog (郭霖)独家发布

在开发中,经常会遇到键盘挡住输入框的情况,比如登录界面或注册界面,弹出的软键盘把登录或注册按钮挡住了,用户必须把软键盘收起,才能点击相应按钮,这样的用户体验非常不好。像微信则直接把登录按钮做在输入框的上面,但有很多情况下,这经常满足不了需求。同时如果输入框特别多的情况下,点击输入时,当前输入框没被挡住,但是当前输入框下面的输入框却无法获取焦点,必须先把键盘收起,再去获取下面输入框焦点,这样用户体验也非常不好,那有什么办法呢? 
系统的adjustResize和adjustPan有什么区别,他们使用时的注意事项,有什么系统要求及蔽端呢?

下面对几种在开发中常用的方法进行总结:

方法一:非透明状态栏下使用adjustResize和adjustPan,或是透明状态栏下使用fitsSystemWindows=true属性

主要实现方法: 
在AndroidManifest.xml对应的Activity里添加 
android:windowSoftInputMode=”adjustPan”或是android:windowSoftInputMode=”adjustResize”属性 
这两种属性的区别,官方的解释是: 
这里写图片描述

这两个属性作用都是为了调整界面使键盘不挡住输入框 ,我这里对这两种属性使用场景、优缺点、注意事项进行了全方面总结,不知大家平时使用时是否注意到了。

属性注意事项优缺点失效情况适用情况
adjustResize需要界面本身可调整尺寸
如在布局添加ScrollView,或输入控件属于RecycleView/ListView某一项
优点:1.不会把标题栏顶出当前布局;
2.有多项输入时,当前输入框下面的输入框可上下滑动输入 
缺点:1.需要界面本身可调整尺寸;
2. 全屏时失效
1.Activity主窗口尺寸无法调整;
2.Activity全屏
3.android5.0以上通过style设置沉浸式状态栏模式而不设置fitSystemWindow为true
非全屏或是非沉浸式状态栏输入界面,输入框比较多
adjustPan页面不会重新布局,当前输入框和键盘会直接将当前输入框以上界面整体向上平移,这样即使界面包含标题栏,也会被顶上去优点: 使用简单,不需要界面本身可调整尺寸,不会有失效情况 
缺点: 会把标题栏顶出当前布局;有多项输入时,当前输入框下面的输入框无法输入,必须收起键盘显示输入框再输入
有少量输入项,且输入量居界面上方
fitsSystemWindows如果多个View设置了fitsSystemWindows=”true”,只有初始的view起作用,都是从第一个设置了fitsSystemWindows的view开始计算padding优点:使用简单,需要沉浸式状态栏的界面,不需要自己计算padding状态栏的高度 
缺点:使用有限制
1.View 的其他 padding 值被重新改写了
2.手机系统版本>=android 4.4
1.界面全屏
2.设置界面主题为沉浸式状态栏
  • adjustResize失效情况:activity设置了全屏属性指Theme.Light.NotittleBar.Fullscreen(键盘弹起时会将标题栏也推上去)或者设置了activity对应的主题中android:windowTranslucentStatus属性,设置方式为:android:windowTranslucentStatus=true,这时如果对应的页面上含有输入框,将会导致点击输入框时软键盘弹出后键盘覆盖输入框,导致输入框看不见。
  • fitsSystemWindows=”true”,只有初始的view起作用:如果在布局中不是最外层控件设置fitsSystemWindows=”true”, 那么设置的那个控件高度会多出一个状态栏高度。若有多个view设置了,因第一个view已经消耗掉insect,其他view设置了也会被系统忽略。

假设原始界面是一个LinearLayout包含若干EditText,如下图所示,在分别使用两种属性时的表现。

这里写图片描述

1、adjustPan

整个界面向上平移,使输入框露出,它不会改变界面的布局;界面整体可用高度还是屏幕高度,这个可以通过下面的截图看出,如点击输入框6,输入框会被推到键盘上方,但输入框1被顶出去了,如果界面包含标题栏,也会被顶出去。

这里写图片描述

2、adjustResize

需要界面的高度是可变的,或者说Activity主窗口的尺寸是可以调整的,如果不能调整,则不会起作用。 
例如:Activity的xml布局中只有一个LinearLayout包含若干EditText,在Activity的AndroidMainfest.xml中设置android:windowSoftInputMode=”adjustResize”属性,点击输入框6, 发现软键盘挡住了输入框6,并没有调整,如下图所示:

这里写图片描述

但使用这两种属性,我们可以总结以下几点: 
1) 使用adjustPan, 如果需要输入的项比较多时,点击输入框,当前输入项会被顶到软键盘上方,但若当前输入框下面还有输入项时,却需要先收起键盘,再点击相应的输入项才能输入。这样操作太繁琐了,对于用户体验不大好; 
2) adjustResize的使用,需要界面本身可显示的窗口内容能调整,可结合scrollview使用;

方法二:在界面最外层布局包裹ScrollView

1、只使用ScrollView

在相应界面的xml布局中,最外层添加一个ScrollView,不在AndroidMainfest.xml中设置任何android:windowSoftInputMode属性,此时点击输入框,输入框均不会被软键盘档住。即使当前输入框下方也有输入框,在键盘显示的情况下,也可以通过上下滑动界面来输入,而不用先隐藏键盘,点击下方输入框,再显示键盘输入。 
我们可以根据Android Studio的Inspect Layout工具来查看界面真正占用的布局高度,工具在 
这里写图片描述

通过该工具,我们看到: 
界面真正能用的高度=屏幕高度-状态栏高度-软键盘高度 
界面中蓝框是真正界面所用的高度:

这里写图片描述

2、ScrollView+adjustPan

我们再在该类的AndroidMainfest.xml中设置windowSoftInputMode属性为adjustPan,

<span style="color:#000000"><span style="color:#000080"><<span style="color:#000080">activity</span> <span style="color:#008080">android:name</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">".TestInputActivity"</span></span></span><span style="color:#000080"><span style="color:#008080">android:windowSoftInputMode</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"adjustPan"</span></span></span><span style="color:#000080">></span></span>

发现当前输入框不会被挡住,但是输入框比较多时,在有键盘显示时,界面上下滑动,但只能滑动部分,且如果输入框在界面靠下方时,点击输入框,标题栏也会被顶出去,如下图所示: 
这里写图片描述

我们借助Inspect Layout工具查看此设置布局可用高度,从下图可以看出,此时布局可用高度是屏幕的高度,上下滑动也只是此屏的高度,在输入框9以下的输入框滑不出来,向上滑动,也只能滑到输入框1。 
这里写图片描述

3、ScrollView+adjustResize

我们前面说过adjustResize的使用必须界面布局高度是可变的,如最外层套个ScrollView或是界面可收缩的,才起作用。这里在该类的AndroidMainfest.xml中设置windowSoftInputMode属性为adjustResize,

<span style="color:#000000"><span style="color:#000080"><<span style="color:#000080">activity</span> <span style="color:#008080">android:name</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">".TestInputActivity"</span></span></span><span style="color:#000080"><span style="color:#008080">android:windowSoftInputMode</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"adjustResize"</span></span></span><span style="color:#000080">></span></span>

发现效果和1不设置任何windowSoftInputMode属性类似,其使用高度也是:屏幕高度-状态栏高度-软键盘高度 
这里写图片描述 
我们再来看看windowSoftInputMode默认属性值stateUnspecified: 
这里写图片描述 
可以看出,系统将选择合适的状态,也就是在界面最外层包含一层ScrollView时,设置默认属性值stateUnspecified其实就是adjustResize属性。

但以下两方面无法满足需求:

1) 当Activity设置成全屏fullscreen模式时或是使用沉浸式状态栏时,界面最外层包裹 ScrollView,当输入框超过一屏,当前输入框下面的输入框并不能上下滑动来输入,情况类似于ScrollView+adjustPan,只能滑动部分,通过Inspect Layout也可以看到,界面可用高度是整个屏幕高度,并不会进行调整高度。即使设置adjustResize,也不起作用。 
2) 如果是类似于注册界面或是登录界面,键盘会挡住输入框下面的登录按钮。

沉浸式状态栏/透明状态栏情况下

自android系统4.4(API>=19)就开始支持沉浸式状态栏,当使用觉System windows(系统窗口),显示系统一些属性和操作区域,如 最上方的状态及没有实体按键的最下方的虚拟导航栏。 
android:fitsSystemWindows=“true”会使得屏幕上的可布局空间位于状态栏下方与导航栏上方

方法三:使用scrollTo方法,当键盘弹起时,让界面整体上移;键盘收起,让界面整体下移

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

1、主要实现步骤:

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

<span style="color:#000000"><span style="color:#000080"><<span style="color:#000080">RelativeLayout</span> <span style="color:#008080">xmlns:android</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"http://schemas.android.com/apk/res/android"</span></span></span><span style="color:#000080"><span style="color:#008080">xmlns:tools</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"http://schemas.android.com/tools"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_width</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"match_parent"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_height</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"match_parent"</span></span></span><span style="color:#000080"><span style="color:#008080">android:id</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@+id/main"</span></span></span><span style="color:#000080"><span style="color:#008080">tools:context</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"com.example.liubin1.softkeyboardhelper.MainActivity"</span></span></span><span style="color:#000080">></span><span style="color:#000080"><<span style="color:#000080">EditText</span><span style="color:#008080">android:id</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@+id/name"</span></span></span><span style="color:#000080"><span style="color:#008080">android:hint</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"请输入用户名:"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_centerInParent</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"true"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_width</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"match_parent"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_height</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"50dp"</span></span></span><span style="color:#000080">/></span><span style="color:#000080"><<span style="color:#000080">EditText</span><span style="color:#008080">android:id</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@+id/pas"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_below</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@id/name"</span></span></span><span style="color:#000080"><span style="color:#008080">android:hint</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"请输入密码:"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_centerInParent</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"true"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_width</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"match_parent"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_height</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"50dp"</span></span></span><span style="color:#000080">/></span><span style="color:#000080"><<span style="color:#000080">Button</span><span style="color:#008080">android:id</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@+id/login_btn"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_below</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"@id/rpas"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_centerHorizontal</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"true"</span></span></span><span style="color:#000080"><span style="color:#008080">android:text</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"登录"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_width</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"180dp"</span></span></span><span style="color:#000080"><span style="color:#008080">android:layout_height</span>=</span><span style="color:#219161"><span style="color:#000080"><span style="color:#219161">"50dp"</span></span></span><span style="color:#000080"> /></span>
<span style="color:#000080"></<span style="color:#000080">RelativeLayout</span>></span></span>

先获取到最外层控件

<span style="color:#000000"><span style="color:#19469d">RelativeLayout</span> main = (RelativeLayout) findViewById(R.id.main);</span>

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

<span style="color:#000000"><span style="color:#19469d">Button</span> login_btn = (Button) findViewById(R.id.login_btn);</span>

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

<span style="color:#000000"><span style="color:#408080"><em><span style="color:#408080"><em>//在Activity的onCreate里添加如下方法</em></span></em></span>
addLayoutListener(main,login_btn);
<span style="color:#408080"><em><span style="color:#408080"><em>/** * addLayoutListener方法如下 *</em></span><span style="color:#408080"><em> @param</em></span><span style="color:#408080"><em> main 根布局 *</em></span><span style="color:#408080"><em> @param</em></span><span style="color:#408080"><em> scroll 需要显示的最下方View */</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">addLayoutListener</span></span><span style="color:#0000ff">(</span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">final</span></span></span><span style="color:#0000ff"> View main, </span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">final</span></span></span><span style="color:#0000ff"> View scroll)</span> {main.getViewTreeObserver().addOnGlobalLayoutListener(<span style="color:#954121"><span style="color:#954121">new</span></span> ViewTreeObserver.OnGlobalLayoutListener() {@Override<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">onGlobalLayout</span></span><span style="color:#0000ff">()</span> {Rect rect = <span style="color:#954121"><span style="color:#954121">new</span></span> Rect();<span style="color:#408080"><em><span style="color:#408080"><em>//1、获取main在窗体的可视区域</em></span></em></span>main.getWindowVisibleDisplayFrame(rect);<span style="color:#408080"><em><span style="color:#408080"><em>//2、获取main在窗体的不可视区域高度,在键盘没有弹起时,main.getRootView().getHeight()调节度应该和rect.bottom高度一样</em></span></em></span><span style="color:#954121"><span style="color:#954121">int</span></span> mainInvisibleHeight = main.getRootView().getHeight() - rect.bottom;<span style="color:#954121"><span style="color:#954121">int</span></span> screenHeight = main.getRootView().getHeight();<span style="color:#408080"><em><span style="color:#408080"><em>//屏幕高度</em></span></em></span><span style="color:#408080"><em><span style="color:#408080"><em>//3、不可见区域大于屏幕本身高度的1/4:说明键盘弹起了</em></span></em></span><span style="color:#954121"><span style="color:#954121">if</span></span> (mainInvisibleHeight > screenHeight / <span style="color:#40a070"><span style="color:#40a070">4</span></span>) {<span style="color:#954121"><span style="color:#954121">int</span></span>[] location = <span style="color:#954121"><span style="color:#954121">new</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span>[<span style="color:#40a070"><span style="color:#40a070">2</span></span>];scroll.getLocationInWindow(location);<span style="color:#408080"><em><span style="color:#408080"><em>// 4、获取Scroll的窗体坐标,算出main需要滚动的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">int</span></span> srollHeight = (location[<span style="color:#40a070"><span style="color:#40a070">1</span></span>] + scroll.getHeight()) - rect.bottom;<span style="color:#408080"><em><span style="color:#408080"><em>//5、让界面整体上移键盘的高度</em></span></em></span>main.scrollTo(<span style="color:#40a070"><span style="color:#40a070">0</span></span>, srollHeight);} <span style="color:#954121"><span style="color:#954121">else</span></span> {<span style="color:#408080"><em><span style="color:#408080"><em>//3、不可见区域小于屏幕高度1/4时,说明键盘隐藏了,把界面下移,移回到原有高度</em></span></em></span>main.scrollTo(<span style="color:#40a070"><span style="color:#40a070">0</span></span>, <span style="color:#40a070"><span style="color:#40a070">0</span></span>);}}});}
}</span>

2、实现原理:

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

具体实现代码见demo中的LoginActivity类。

3、弊端:

此种方法需要在当前界面写比较多的代码,在某些手机上,若输入时,软键盘高度是可变的,如中英文切换,高度变化时,会发现适配的不大好。如下图: 
这里写图片描述 
从上图可以看出,如果键盘高度变化,键盘还是会挡住登录按钮。

方法四:适配键盘高度变化情况,当键盘弹起时,让界面整体上移;键盘收起,让界面整体下移

此方法主要是通过在需要移动的控件外套一层scrollView,同时最布局最外层使用自定义view监听键盘弹出状态,计算键盘高度,再进行计算需要移动的位置,这个和方法三有点类似,但能适配键盘高度变化情况。

实现步骤

(1) 先写自定义View,实时临听界面键盘弹起状态,计算键盘高度

<span style="color:#000000"><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#445588"><strong><span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">class</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>KeyboardLayout</strong></span></strong></span></strong></span> <span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">extends</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>FrameLayout</strong></span></strong></span></strong></span> {</strong></span><span style="color:#954121"><span style="color:#954121">private</span></span> KeyboardLayoutListener mListener;<span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">boolean</span></span> mIsKeyboardActive = <span style="color:#954121"><span style="color:#954121">false</span></span>; <span style="color:#408080"><em><span style="color:#408080"><em>//输入法是否激活</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> mKeyboardHeight = <span style="color:#40a070"><span style="color:#40a070">0</span></span>; <span style="color:#408080"><em><span style="color:#408080"><em>// 输入法高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#19469d"><span style="color:#19469d">KeyboardLayout</span></span><span style="color:#0000ff">(Context context)</span> {<span style="color:#954121"><span style="color:#954121">this</span></span>(context, <span style="color:#954121"><span style="color:#954121">null</span></span>, <span style="color:#40a070"><span style="color:#40a070">0</span></span>);}<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#19469d"><span style="color:#19469d">KeyboardLayout</span></span><span style="color:#0000ff">(Context context, AttributeSet attrs)</span> {<span style="color:#954121"><span style="color:#954121">this</span></span>(context, attrs, <span style="color:#40a070"><span style="color:#40a070">0</span></span>);}<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#19469d"><span style="color:#19469d">KeyboardLayout</span></span><span style="color:#0000ff">(Context context, AttributeSet attrs, </span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">int</span></span></span><span style="color:#0000ff"> defStyleAttr)</span> {<span style="color:#954121"><span style="color:#954121">super</span></span>(context, attrs, defStyleAttr);<span style="color:#408080"><em><span style="color:#408080"><em>// 监听布局变化</em></span></em></span>getViewTreeObserver().addOnGlobalLayoutListener(<span style="color:#954121"><span style="color:#954121">new</span></span> KeyboardOnGlobalChangeListener());}<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">setKeyboardListener</span></span><span style="color:#0000ff">(KeyboardLayoutListener listener)</span> {mListener = listener;}<span style="color:#954121"><span style="color:#954121">public</span></span> KeyboardLayoutListener <span style="color:#19469d"><span style="color:#19469d">getKeyboardListener</span></span><span style="color:#0000ff">()</span> {<span style="color:#954121"><span style="color:#954121">return</span></span> mListener;}<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">boolean</span></span> <span style="color:#19469d"><span style="color:#19469d">isKeyboardActive</span></span><span style="color:#0000ff">()</span> {<span style="color:#954121"><span style="color:#954121">return</span></span> mIsKeyboardActive;}<span style="color:#408080"><em><span style="color:#408080"><em>/** * 获取输入法高度 * *</em></span><span style="color:#408080"><em> @return</em></span><span style="color:#408080"><em> */</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> <span style="color:#19469d"><span style="color:#19469d">getKeyboardHeight</span></span><span style="color:#0000ff">()</span> {<span style="color:#954121"><span style="color:#954121">return</span></span> mKeyboardHeight;}<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#445588"><strong><span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">interface</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>KeyboardLayoutListener</strong></span></strong></span></strong></span> {</strong></span><span style="color:#408080"><em><span style="color:#408080"><em>/** *</em></span><span style="color:#408080"><em> @param</em></span><span style="color:#408080"><em> isActive 输入法是否激活 *</em></span><span style="color:#408080"><em> @param</em></span><span style="color:#408080"><em> keyboardHeight 输入法面板高度 */</em></span></em></span><span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d">onKeyboardStateChanged</span><span style="color:#0000ff">(</span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">boolean</span></span></span><span style="color:#0000ff"> isActive, </span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">int</span></span></span><span style="color:#0000ff"> keyboardHeight)</span>;}<span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#445588"><strong><span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">class</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>KeyboardOnGlobalChangeListener</strong></span></strong></span></strong></span> <span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">implements</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>ViewTreeObserver</strong></span></strong></span></strong></span><span style="color:#445588"><strong>.</strong></span><span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>OnGlobalLayoutListener</strong></span></strong></span></strong></span> {</strong></span><span style="color:#954121"><span style="color:#954121">int</span></span> mScreenHeight = <span style="color:#40a070"><span style="color:#40a070">0</span></span>;<span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> <span style="color:#19469d"><span style="color:#19469d">getScreenHeight</span></span><span style="color:#0000ff">()</span> {<span style="color:#954121"><span style="color:#954121">if</span></span> (mScreenHeight > <span style="color:#40a070"><span style="color:#40a070">0</span></span>) {<span style="color:#954121"><span style="color:#954121">return</span></span> mScreenHeight;}mScreenHeight = ((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getHeight();<span style="color:#954121"><span style="color:#954121">return</span></span> mScreenHeight;}@Override<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">onGlobalLayout</span></span><span style="color:#0000ff">()</span> {Rect rect = <span style="color:#954121"><span style="color:#954121">new</span></span> Rect();<span style="color:#408080"><em><span style="color:#408080"><em>// 获取当前页面窗口的显示范围</em></span></em></span>((Activity) getContext()).getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);<span style="color:#954121"><span style="color:#954121">int</span></span> screenHeight = getScreenHeight();<span style="color:#954121"><span style="color:#954121">int</span></span> keyboardHeight = screenHeight - rect.bottom; <span style="color:#408080"><em><span style="color:#408080"><em>// 输入法的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">boolean</span></span> isActive = <span style="color:#954121"><span style="color:#954121">false</span></span>;<span style="color:#954121"><span style="color:#954121">if</span></span> (Math.abs(keyboardHeight) > screenHeight / <span style="color:#40a070"><span style="color:#40a070">4</span></span>) {isActive = <span style="color:#954121"><span style="color:#954121">true</span></span>; <span style="color:#408080"><em><span style="color:#408080"><em>// 超过屏幕五分之一则表示弹出了输入法</em></span></em></span>mKeyboardHeight = keyboardHeight;}mIsKeyboardActive = isActive;<span style="color:#954121"><span style="color:#954121">if</span></span> (mListener != <span style="color:#954121"><span style="color:#954121">null</span></span>) {mListener.onKeyboardStateChanged(isActive, keyboardHeight);}}}}</span>

(2) xml文件编写,在界面最外层套上自定义view,在需要滚动的控件外层添加scrollView

<span style="color:#000000"><com.example.smilexie.softboradblockedittext.util.KeyboardLayoutandroid:id=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@+</span>id/main_ll"</span></span>android:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_bg"</span></span>android:orientation=<span style="color:#219161"><span style="color:#219161">"vertical"</span></span>><ScrollViewandroid:id=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@+</span>id/login_ll"</span></span>android:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>><LinearLayoutandroid:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:orientation=<span style="color:#219161"><span style="color:#219161">"vertical"</span></span>><LinearLayoutandroid:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginRight=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginTop=<span style="color:#219161"><span style="color:#219161">"200dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_input_field_icon"</span></span>android:orientation=<span style="color:#219161"><span style="color:#219161">"horizontal"</span></span>><ImageViewandroid:layout_width=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_gravity=<span style="color:#219161"><span style="color:#219161">"center_vertical"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_yonghuming_icon"</span></span> /><EditTextandroid:id=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@+</span>id/ui_username_input"</span></span>style=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@style</span>/editext_input_style"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"40dp"</span></span>android:layout_marginRight=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@null</span>"</span></span>android:hint=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@string</span>/login_hint_username"</span></span>android:imeOptions=<span style="color:#219161"><span style="color:#219161">"actionNext"</span></span>android:textColor=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@android</span>:color/white"</span></span>android:textColorHint=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@android</span>:color/white"</span></span>><requestFocus /><<span style="color:#bb6688">/EditText></</span>LinearLayout><LinearLayoutandroid:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginRight=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginTop=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_input_field_icon"</span></span>android:orientation=<span style="color:#219161"><span style="color:#219161">"horizontal"</span></span>><ImageViewandroid:layout_width=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_gravity=<span style="color:#219161"><span style="color:#219161">"center_vertical"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_mima_icon"</span></span> /><EditTextandroid:id=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@+</span>id/ui_password_input"</span></span>style=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@style</span>/editext_input_style"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"40dp"</span></span>android:layout_marginRight=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@null</span>"</span></span>android:hint=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@string</span>/login_hint_pwd"</span></span>android:imeOptions=<span style="color:#219161"><span style="color:#219161">"actionDone"</span></span>android:inputType=<span style="color:#219161"><span style="color:#219161">"textPassword"</span></span>android:textColor=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@android</span>:color/white"</span></span>android:textColorHint=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@android</span>:color/white"</span></span>><<span style="color:#bb6688">/EditText></</span>LinearLayout><Buttonandroid:id=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@+</span>id/login_btn"</span></span>android:layout_width=<span style="color:#219161"><span style="color:#219161">"match_parent"</span></span>android:layout_height=<span style="color:#219161"><span style="color:#219161">"wrap_content"</span></span>android:layout_marginLeft=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginRight=<span style="color:#219161"><span style="color:#219161">"50dp"</span></span>android:layout_marginTop=<span style="color:#219161"><span style="color:#219161">"20dp"</span></span>android:background=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@mipmap</span>/login_button_bg_icon"</span></span>android:text=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@string</span>/login"</span></span>android:textColor=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@color</span>/titlebar_main_color"</span></span>android:textSize=<span style="color:#219161"><span style="color:#219161">"<span style="color:#008080">@dimen</span>/font_normal"</span></span> /><<span style="color:#bb6688">/LinearLayout></</span>ScrollView><<span style="color:#bb6688">/com.example.smilexie.softboradblockedittext.util.KeyboardLayout></span></span>

(3) Activity调用,自定义view控件添加键盘响应,在键盘变化时调用scrollView的smoothScrollTo去滚动界面

<span style="color:#000000"><span style="color:#408080"><em><span style="color:#408080"><em>/** * 监听键盘状态,布局有变化时,靠scrollView去滚动界面 */</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">addLayoutListener</span></span><span style="color:#0000ff">()</span> {bindingView.mainLl.setKeyboardListener(<span style="color:#954121"><span style="color:#954121">new</span></span> KeyboardLayout.KeyboardLayoutListener() {@Override<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">onKeyboardStateChanged</span></span><span style="color:#0000ff">(</span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">boolean</span></span></span><span style="color:#0000ff"> isActive, </span><span style="color:#954121"><span style="color:#0000ff"><span style="color:#954121">int</span></span></span><span style="color:#0000ff"> keyboardHeight)</span> {Log.e(<span style="color:#219161"><span style="color:#219161">"onKeyboardStateChanged"</span></span>, <span style="color:#219161"><span style="color:#219161">"isActive:"</span></span> + isActive + <span style="color:#219161"><span style="color:#219161">" keyboardHeight:"</span></span> + keyboardHeight);<span style="color:#954121"><span style="color:#954121">if</span></span> (isActive) {scrollToBottom();}}});}<span style="color:#408080"><em><span style="color:#408080"><em>/** * 弹出软键盘时将SVContainer滑到底 */</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">scrollToBottom</span></span><span style="color:#0000ff">()</span> {bindingView.loginLl.postDelayed(<span style="color:#954121"><span style="color:#954121">new</span></span> Runnable() {@Override<span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">run</span></span><span style="color:#0000ff">()</span> {bindingView.loginLl.smoothScrollTo(<span style="color:#40a070"><span style="color:#40a070">0</span></span>, bindingView.loginLl.getBottom() + SoftKeyInputHidWidget.getStatusBarHeight(LoginActivityForDiffkeyboardHeight.<span style="color:#954121"><span style="color:#954121">this</span></span>));}}, <span style="color:#40a070"><span style="color:#40a070">100</span></span>);}</span>

具体实现代码见demo中的LoginActivityForDiffkeyboardHeight类。实现效果如下: 
这里写图片描述 
可以看到键盘高度变化了,也不会影响界面布局

方法五:监听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类具体代码如下:

<span style="color:#000000"><span style="color:#408080"><em><span style="color:#408080"><em>/** * 解决键盘档住输入框 * Created by SmileXie on 2017/4/3. */</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#445588"><strong><span style="color:#954121"><span style="color:#445588"><strong><span style="color:#954121">class</span></strong></span></span> <span style="color:#445588"><strong><span style="color:#445588"><strong><span style="color:#445588"><strong>SoftHideKeyBoardUtil</strong></span></strong></span></strong></span> {</strong></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">static</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">assistActivity</span></span> <span style="color:#0000ff">(Activity activity)</span> {<span style="color:#954121"><span style="color:#954121">new</span></span> SoftHideKeyBoardUtil(activity);}<span style="color:#954121"><span style="color:#954121">private</span></span> View mChildOfContent;<span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> usableHeightPrevious;<span style="color:#954121"><span style="color:#954121">private</span></span> FrameLayout.LayoutParams frameLayoutParams;<span style="color:#408080"><em><span style="color:#408080"><em>//为适应华为小米等手机键盘上方出现黑条或不适配</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> contentHeight;<span style="color:#408080"><em><span style="color:#408080"><em>//获取setContentView本来view的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">boolean</span></span> isfirst = <span style="color:#954121"><span style="color:#954121">true</span></span>;<span style="color:#408080"><em><span style="color:#408080"><em>//只用获取一次</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span>  <span style="color:#954121"><span style="color:#954121">int</span></span> statusBarHeight;<span style="color:#408080"><em><span style="color:#408080"><em>//状态栏高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#19469d"><span style="color:#19469d">SoftHideKeyBoardUtil</span></span><span style="color:#0000ff">(Activity activity)</span> {<span style="color:#408080"><em><span style="color:#408080"><em>//1、找到Activity的最外层布局控件,它其实是一个DecorView,它所用的控件就是FrameLayout</em></span></em></span>FrameLayout content = (FrameLayout) activity.findViewById(android.R.id.content);<span style="color:#408080"><em><span style="color:#408080"><em>//2、获取到setContentView放进去的View</em></span></em></span>mChildOfContent = content.getChildAt(<span style="color:#40a070"><span style="color:#40a070">0</span></span>);<span style="color:#408080"><em><span style="color:#408080"><em>//3、给Activity的xml布局设置View树监听,当布局有变化,如键盘弹出或收起时,都会回调此监听 </em></span></em></span>mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener(<span style="color:#954121"><span style="color:#954121">new</span></span> ViewTreeObserver.OnGlobalLayoutListener() {<span style="color:#408080"><em><span style="color:#408080"><em>//4、软键盘弹起会使GlobalLayout发生变化</em></span></em></span><span style="color:#954121"><span style="color:#954121">public</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">onGlobalLayout</span></span><span style="color:#0000ff">()</span> {<span style="color:#954121"><span style="color:#954121">if</span></span> (isfirst) {contentHeight = mChildOfContent.getHeight();<span style="color:#408080"><em><span style="color:#408080"><em>//兼容华为等机型</em></span></em></span>isfirst = <span style="color:#954121"><span style="color:#954121">false</span></span>;}<span style="color:#408080"><em><span style="color:#408080"><em>//5、当前布局发生变化时,对Activity的xml布局进行重绘</em></span></em></span>possiblyResizeChildOfContent();}});<span style="color:#408080"><em><span style="color:#408080"><em>//6、获取到Activity的xml布局的放置参数</em></span></em></span>frameLayoutParams = (FrameLayout.LayoutParams) mChildOfContent.getLayoutParams();}<span style="color:#408080"><em><span style="color:#408080"><em>// 获取界面可用高度,如果软键盘弹起后,Activity的xml布局可用高度需要减去键盘高度 </em></span></em></span><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">void</span></span> <span style="color:#19469d"><span style="color:#19469d">possiblyResizeChildOfContent</span></span><span style="color:#0000ff">()</span> {<span style="color:#408080"><em><span style="color:#408080"><em>//1、获取当前界面可用高度,键盘弹起后,当前界面可用布局会减少键盘的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">int</span></span> usableHeightNow = computeUsableHeight();<span style="color:#408080"><em><span style="color:#408080"><em>//2、如果当前可用高度和原始值不一样</em></span></em></span><span style="color:#954121"><span style="color:#954121">if</span></span> (usableHeightNow != usableHeightPrevious) {<span style="color:#408080"><em><span style="color:#408080"><em>//3、获取Activity中xml中布局在当前界面显示的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">int</span></span> usableHeightSansKeyboard = mChildOfContent.getRootView().getHeight();<span style="color:#408080"><em><span style="color:#408080"><em>//4、Activity中xml布局的高度-当前可用高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">int</span></span> heightDifference = usableHeightSansKeyboard - usableHeightNow;<span style="color:#408080"><em><span style="color:#408080"><em>//5、高度差大于屏幕1/4时,说明键盘弹出</em></span></em></span><span style="color:#954121"><span style="color:#954121">if</span></span> (heightDifference > (usableHeightSansKeyboard/<span style="color:#40a070"><span style="color:#40a070">4</span></span>)) {<span style="color:#408080"><em><span style="color:#408080"><em>// 6、键盘弹出了,Activity的xml布局高度应当减去键盘高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">if</span></span> (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT){frameLayoutParams.height = usableHeightSansKeyboard - heightDifference + statusBarHeight;} <span style="color:#954121"><span style="color:#954121">else</span></span> {frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;}} <span style="color:#954121"><span style="color:#954121">else</span></span> {frameLayoutParams.height = contentHeight;}<span style="color:#408080"><em><span style="color:#408080"><em>//7、 重绘Activity的xml布局</em></span></em></span>mChildOfContent.requestLayout();usableHeightPrevious = usableHeightNow;}}<span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> <span style="color:#19469d"><span style="color:#19469d">computeUsableHeight</span></span><span style="color:#0000ff">()</span> {Rect r = <span style="color:#954121"><span style="color:#954121">new</span></span> Rect();mChildOfContent.getWindowVisibleDisplayFrame(r);<span style="color:#408080"><em><span style="color:#408080"><em>// 全屏模式下:直接返回r.bottom,r.top其实是状态栏的高度</em></span></em></span><span style="color:#954121"><span style="color:#954121">return</span></span> (r.bottom - r.top);}
}</span>

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

<span style="color:#000000"><span style="color:#19469d">FrameLayout</span> content = (FrameLayout) activity.findViewById(android.R.id.content);</span>

所以content.getChildAt(0)获取到的mChildOfContent,也就是我们用setContentView放进去的View。 
(2) 给我们的Activity的xml布局View设置一个Listener监听

<span style="color:#000000">mChildOfContent.getViewTreeObserver().addOnGlobalLayoutListener({ possiblyResizeChildOfContent();
});</span>

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

<span style="color:#000000"><span style="color:#954121"><span style="color:#954121">private</span></span> <span style="color:#954121"><span style="color:#954121">int</span></span> <span style="color:#19469d"><span style="color:#19469d">computeUsableHeight</span></span><span style="color:#0000ff">()</span> {Rect rect = <span style="color:#954121"><span style="color:#954121">new</span></span> Rect();mChildOfContent.getWindowVisibleDisplayFrame(rect);<span style="color:#408080"><em><span style="color:#408080"><em>// rect.top其实是状态栏的高度,如果是全屏主题,直接 return rect.bottom就可以了</em></span></em></span><span style="color:#954121"><span style="color:#954121">return</span></span> (rect.bottom - rect.top);
}</span>

如下图所示: 
这里写图片描述 
(4) 重设高度, 我们计算出的可用高度,是目前在视觉效果上能看到的界面高度。但当前界面的实际高度是比可用高度要多出一个软键盘的距离的。

具体实现代码见demo中的TransStatusbarWisthAssistActivity类。

注意:如果既使用了沉浸式状态栏,又加了fitSystetemWindow=true属性,就需要在AndroidMainfest.xml注册Activity的地方添加上以下属性。因为你两种都用,系统不知道用哪种了。fitSystetemWindow已经有resize屏幕的作用。

<span style="color:#000000">android:windowSoftInputMode=<span style="color:#219161"><span style="color:#219161">"stateHidden|adjustPan"</span></span></span>

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

总结:

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

  • 方法一:优点:使用简单,只需在Activity的AndroidMainfest.xml中设置windowSoftInput属性即可。 
    注意点:adjustResize属性必须要界面大小可以自身改变; 
    缺点:当输入框比较多时,当前输入框下方的输入框会初键盘挡住,须收起键盘再进入输入;使用adjustPan,输入框较多时,因它是把界面当成一个整体,只会显示一屏的高度,会把ActionBar顶上去。

  • 方法二:优点:使用简单,只需在Activity的最外层布局包裹一个ScrollView即可。 
    注意点:不可使用adjustPan属性,否则ScrollView失效; 
    缺点:对于全屏时,在键盘显示时,无法上下滑动界面达到输入的目的;

  • 方法三:优点:可以解决全屏时,键盘挡入按钮问题。 
    缺点:只要有此需求的Activity均需要获取到最外层控件和最后一个控件,监测键盘是否弹出,再调用控件的scrollTo方法对界面整体上移或是下移。代码冗余。对于键盘高度变化时,适配不好。

  • 方法四:优点:可以解决全屏时,键盘挡入按钮问题。 
    缺点:只要有此需求的Activity均需要获取到最外层控件和最后一个控件,布局多出一层。

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

综上所述: 
1) 当输入框比较少时,界面只有一个输入框时,可以通过方法一设置adjustPan; 
2) 如果对于非全屏/非沉浸式状态栏需求,只需要使用方法二ScrollView+adjustResize; 
3) 如果对于使用沉浸式状态栏,使用fitSystemWindow=true属性,按道理android系统已经做好适配,键盘不会挡住输入框; 
4) 如果全屏/沉浸式状态栏界面,类似于登录界面,有需要把登录键钮或是评论按钮也顶起,如果键盘没有变化需求,可以使用方法三,若需要适配键盘高度变化,则需要使用方法四; 
5) 如果界面使用全屏或沉浸式状态栏,没有使用fitSystemWindow=true属性,一般如需要用到抽屈而且状态栏颜色也需要跟着变化,则选择方法五更恰当。

代码传送门:https://github.com/xiewenfeng/SoftboradBlockEdittext 如果有哪写的不对或是不好的地方,欢迎大家提出宝贵意见,一起探讨,共同进步。

这篇关于android全屏/沉浸式状态栏下,各种键盘挡住输入框解决办法[转]的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/535104

相关文章

JavaScript全屏,监听页面是否全屏

在JavaScript中,直接监听浏览器是否进入全屏模式并不直接支持,因为全屏API主要是关于请求和退出全屏模式的,而没有直接的监听器可以告知页面何时进入或退出全屏模式。但是,你可以通过在你的代码中跟踪全屏状态的改变来模拟这个功能。 以下是一个基本的示例,展示了如何使用全屏API来请求全屏模式,并在请求成功或失败时更新一个状态变量: javascriptlet isInFullscreen =

iOS HTTPS证书不受信任解决办法

之前开发App的时候服务端使用的是自签名的证书,导致iOS开发过程中调用HTTPS接口时,证书不被信任 - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAu

Eclipse+ADT与Android Studio开发的区别

下文的EA指Eclipse+ADT,AS就是指Android Studio。 就编写界面布局来说AS可以边开发边预览(所见即所得,以及多个屏幕预览),这个优势比较大。AS运行时占的内存比EA的要小。AS创建项目时要创建gradle项目框架,so,创建项目时AS比较慢。android studio基于gradle构建项目,你无法同时集中管理和维护多个项目的源码,而eclipse ADT可以同时打开

android 免费短信验证功能

没有太复杂的使用的话,功能实现比较简单粗暴。 在www.mob.com网站中可以申请使用免费短信验证功能。 步骤: 1.注册登录。 2.选择“短信验证码SDK” 3.下载对应的sdk包,我这是选studio的。 4.从头像那进入后台并创建短信验证应用,获取到key跟secret 5.根据技术文档操作(initSDK方法写在setContentView上面) 6.关键:在有用到的Mo

android一键分享功能部分实现

为什么叫做部分实现呢,其实是我只实现一部分的分享。如新浪微博,那还有没去实现的是微信分享。还有一部分奇怪的问题:我QQ分享跟QQ空间的分享功能,我都没配置key那些都是原本集成就有的key也可以实现分享,谁清楚的麻烦详解下。 实现分享功能我们可以去www.mob.com这个网站集成。免费的,而且还有短信验证功能。等这分享研究完后就研究下短信验证功能。 开始实现步骤(新浪分享,以下是本人自己实现

Android我的二维码扫描功能发展史(完整)

最近在研究下二维码扫描功能,跟据从网上查阅的资料到自己勉强已实现扫描功能来一一介绍我的二维码扫描功能实现的发展历程: 首页通过网络搜索发现做android二维码扫描功能看去都是基于google的ZXing项目开发。 2、搜索怎么使用ZXing实现自己的二维码扫描:从网上下载ZXing-2.2.zip以及core-2.2-source.jar文件,分别解压两个文件。然后把.jar解压出来的整个c

android 带与不带logo的二维码生成

该代码基于ZXing项目,这个网上能下载得到。 定义的控件以及属性: public static final int SCAN_CODE = 1;private ImageView iv;private EditText et;private Button qr_btn,add_logo;private Bitmap logo,bitmap,bmp; //logo图标private st

Android多线程下载见解

通过for循环开启N个线程,这是多线程,但每次循环都new一个线程肯定很耗内存的。那可以改用线程池来。 就以我个人对多线程下载的理解是开启一个线程后: 1.通过HttpUrlConnection对象获取要下载文件的总长度 2.通过RandomAccessFile流对象在本地创建一个跟远程文件长度一样大小的空文件。 3.通过文件总长度/线程个数=得到每个线程大概要下载的量(线程块大小)。

vue+elementui分页输入框回车与页面中@keyup.enter事件冲突解决

解决这个问题的思路只要判断事件源是哪个就好。el分页的回车触发事件是在按下时,抬起并不会再触发。而keyup.enter事件是在抬起时触发。 so,找不到分页的回车事件那就拿keyup.enter事件搞事情。只要判断这个抬起事件的$event中的锚点样式判断不等于分页特有的样式就可以了 @keyup.enter="allKeyup($event)" //页面上的//js中allKeyup(e

vue+elementui--$message提示框被dialog遮罩层挡住问题解决

最近碰到一个先执行this.$message提示内容,然后接着弹出dialog带遮罩层弹框。那么问题来了,message提示框会默认被dialog遮罩层挡住,现在就是要解决这个问题。 由于都是弹框,问题肯定是出在z-index比重问题。由于用$message方式是写在js中而不是写在html中所以不是很好直接去改样式。 不过好在message组件中提供了customClass 属性,我们可以利用