前言
软键盘监听和EditText的显示问题,在我们的日常开发中基本是不可避免的,当EditText位置靠界面下方时,就需要考虑软键盘和EditText的遮盖问题了。首先,Google自此至终,还没有给我们提供直接监听软件盘弹出和隐藏的相关类和方法,其次,软键盘弹出时,系统提供的Activity的windowSoftInputMode属性,并不能很好的解决项目实际需要,无论是adjustPan的窗口上移(顶部导航栏会被顶出窗口)或者adjustResize的窗口截取(EditText会被遮挡一小部分,同时弹出和隐藏时会有轻微的闪烁)。所以,手动监听软键盘,并以此,根据每个布局中EdiText所处的位置来动态改变布局,才能够避免上述的不足。
效果演示
不带虚拟键的手机效果,Gif里显示的比较快,实际效果比较柔和。
带虚拟键的手机效果(虚拟键的手机刚好没法用AS录屏,自带的录屏压缩Gif后居然是横着的,为了不歪脖子,只能上截屏,真机效果和上图是一样的)
GitHub链接
软键盘监听和EditText显示Demo-----------KeyBordDemo
优点:
1.可以准确监听键盘的弹出和隐藏,UI和动效方面自由度比较高。
2.可以准确的回调键盘弹出的高度,不管是Activty还是Fragment,手机是否带虚拟键,
3.不需考虑EditText的父布局是ScrollView,RelativeLayout或LinearLayout的差异的影响而导致windowSoftInputMode属性失效的问题.
使用限制:
1.需要设置沉浸式布局,所以最低要求Android 4.4及以上:
设置沉浸式布局后,Activity在设置android:windowSoftInputMode="adjustResize|stateHidden" 后,adjustResize的窗口截取效果就会失效,我们要自己控制EditText的位置,所以需要利用这个特性。
2.Activity的主题Theme必须继承自系统主题中的.NoActionBar系列: 带虚拟键的手机若不继承该主题,会导致整个Activity界面延伸至虚拟键中。
开发环境
JAVA1.8
Android Studio 3.0 Canary3
Gradle 4.0-milestone-1
使用
(1)创建MainActivity 和 SecondActivity, 一个内置于SecondActivty的SecondFragment。
(2)MainActivity和SecondFragment的布局很简单,一个FrameLayout,包裹TextView和EditText,TextView至于顶部,用于测试软键盘弹出时,窗口是否上移,EditText至于底部,用于测试软键盘回调的高度是否准确和EditText调整高度时是否存在闪烁。
(3)在AndrodiManifest清单文件中,设置Application的theme 继承自Theme.AppCompat.NoActionBar,同时设置MainActivity 和 SecondActivity的windowSoftInputMode="adjustResize|stateHidden"。
(4)在MainActivity 和 SecondActivity的 setContentView方法之前,做以下设置,使用沉浸式布局。
(5)这个方法就是使用沉浸式布局后,重新设置顶部控件(比如一般app顶部都会设置自定义的导航栏)的偏移量,使之显示正常,建议使用paddingTop,非常简单。
(6)接着,自定义一个IKeyBoardListener接口来监听软键盘的弹出和隐藏,以及软键盘的弹出高度。
(7)然后,获取我们设置给Activity的根布局,比如Demo中的MainActivity就是这个FrameLayout,然后通过ViewTreeObserver.OnGlobalLayoutListener来监听跟布局,不了解ViewTreeObserver的可以查阅相关文章,当软键盘弹出或隐藏时,这个监听器都会回调。
(8)我们需要计算出,系统的状态栏,导航栏,虚拟键的高度 ,然后做以下计算: int heightDiff=screenHeight- (r.bottom-r.top);
heightDiff>navigationBarHeight+statusBarHeight 软键盘弹出heightDiff<=navigationBarHeight+statusBarHeight 软键盘隐藏
即,屏幕高度- Activity的可见边界的上下高度差(上边界r.top即状态栏的底部边界,下边界r.bottom即软键盘的顶部边界) > (系统状态栏高度+导航栏的高度+虚拟键的高度)时,说明软键盘弹出了,弹出高度为: heightDiff-状态栏高度-虚拟键的高度.
反之,则说明软键盘隐藏了.
(9)通过设置的IKeyBoardListener来回调键盘的弹出和隐藏,然后根据visible和keyboardHeight来重新设置EditText布局的底部间距即可,当然这里,也可以设置动画,让EditText布局的抬起和降落更自然。
(10)在acitvity销毁时,记得解除Activity根布局的监听。
结语
不过,我觉得上面的解决方式还是存在一定缺陷,一个是兼容性问题,低于4.4的话需要额外处理,另一个就是,如果不想使用沉浸式布局,那么,目前还没有找到软键盘弹出时,让系统百分百不对界面做窗口上移和窗口截取的方式,需要系统遮盖的效果有时并不会起作用,而QQ和微信聊天界面,是类似一个内页滚动上滑的方式,不过用上面的方式,达到同样的效果并不难。当然,如果有更好的方式,可以分享一下,喜欢我的文章的话,给个赞吧。