Android各种键盘挡住输入框解决办法

作者简介  创微信公众号郭霖 WeChat ID: guolin_blog

潇潇凤儿的博客地址:

http://blog.csdn.net/smileiam

正文

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

系统的 adjustResize 和 adjustPan 有什么区别,他们使用时的注意事项,有什么系统要求及蔽端呢?

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

方法一:windowSoftInputMode:adjustResize和adjustPan

主要实现方法:在 AndroidManifest.xml 对应的Activity里添加 android:windowSoftInputMode=”adjustPan” 或是 android:windowSoftInputMode=”adjustResize”属性

这两种属性的区别,官方的解释是:


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


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

1、只使用ScrollView

在相应界面的xml布局中,最外层添加一个 ScrollView,不在 AndroidMainfest.xml 中设置任何 android:windowSoftInputMode属性,此时点击输入框,输入框均不会被软键盘档住。即使当前输入框下方也有输入框,在键盘显示的情况下,也可以通过上下滑动界面来输入,而不用先隐藏键盘,点击下方输入框,再显示键盘输入。

我们可以根据 Android Studio 的 Inspect Layout 工具来查看界面真正占用的布局高度,工具在:


通过该工具,我们看到:

界面真正能用的高度=屏幕高度-状态栏高度-软键盘高度

界面中蓝框是真正界面所用的高度:


2、ScrollView + adjustPan

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


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


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


3、ScrollView+adjustResize

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


发现效果和 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”会使得屏幕上的可布局空间位于状态栏下方与导航栏上方。

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

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

1、主要实现步骤

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


先获取到最外层控件:

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

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

Buttonlogin_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 控件里

FrameLayoutcontent=(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) 如果大部分界面均使用全屏或沉浸式状态栏,且有此需求,则选择方法四更恰当。


文章原创作者GuoLin 书籍推荐

郭林大神原创android 书籍:《第一行代码 android》

淘宝链接: https://s.click.taobao.com/t?e=m%3D2%26s%3DgKUfuKdAZKocQipKwQzePOeEDrYVVa64K7Vc7tFgwiHjf2vlNIV67p2n%2BQBNMyE6Rku8%2Bpj6eJall3bs%2B3NRhNHnsKI%2BqxhyM0iVZhTFBom4YIorMPnmg8G0g2OJi%2FzmXHfenomYtn5EW9vzeG8LzfPUwktUBEmkxg5p7bh%2BFbQ%3D&pvid=10_106.6.161.154_3367_1490163222155

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容