问题
当输入框处于最底部时
当我们点击输入框,唤起软键盘,会挡住我们的输入框内容 如图
解决方案 1 设置 android:windowSoftInputMode="adjustResize"
这种方式会把页面整体上推 可以看到头部标题整体向上平移了 虽然也能解决问题 但是ui上不友好
解决方案 2 android:windowSoftInputMode="adjustResize" + ScrollView
当时要满足两种情况下才会生效
- 需要界面本身可调整尺寸
- 页面不是全屏时
我们项目中 满足条件1 我们在布局外层包裹NestedScrollView 但是我们是全屏的布局 这就导致第二个条件不满足 所以得寻求解决方案 这样就衍生出了 AndroidBug5497Workaround
既在非全屏模式(即状态栏不透明)
下,将activity
的windowSoftInputMode
的属性设置为:adjustResize
。同时在View
的onSizeChanged(int w, int h, int oldw, int oldh)
里可以得到变化后的尺寸,然后根据前后变化的结果来计算屏幕需要移动的距离。
但是在全屏模式
下,即使将activity
的windowSoftInputMode
的属性设置为:adjustResize
。 在键盘显示时它未将Activity的Screen向上推动,所以你Activity
的view
的根树的尺寸是没有变化的。 在这种情况下,你也就无法得知键盘的尺寸,对根view的作相应的推移。 全屏下的键盘无法Resize的问题从2.1就已经存在了,直到现在google还未给予解决。
终极解决方案 封装好了 上面有详细的备注
-
找到Activity的最外层布局控件,我们知道所有的Activity都是
DecorView
,它就是一个FrameLayout
控件,该控件id是系统写死叫R.id.content
,就是我们setContentView
时,把相应的View放在此FrameLayout
控件里 2.给我们的Activity的xml布局View设置一个Listener监听View.getViewTreeObserver()
可以获取一个ViewTreeObserver
对象------它是一个观察者,用以监听当前View树所发生的变化。这里所注册的addOnGlobalLayoutListener
,就是会在当前的View树的全局布局(GlobalLayout)发生变化、或者其中的View可视状态有变化时,进行通知回调。『软键盘弹出/隐 』都能监听到 -
获取当前界面可用高度
-
重设高度, 我们计算出的可用高度,是目前在视觉效果上能看到的界面高度。但当前界面的实际高度是比可用高度要多出一个软键盘的距离的。 注意:如果既使用了沉浸式状态栏,又加了
fitSystetemWindow=true
属性,就需要在AndroidMainfest.xml
注册Activity
的地方添加上以下属性。因为你两种都用,系统不知道用哪种了。fitSystetemWindow
已经有resize
屏幕的作用。
4.所以content.getChildAt(0)
获取到的mChildOfContent
,也就是我们用setContentView
放进去的View。
kotlin
class AndroidBug5497Workaround private constructor(activity: Activity, needStatusBars: Boolean) {
private var mChildOfContent: View? = null
private var usableHeightPrevious = 0
private var frameLayoutParams: FrameLayout.LayoutParams? = null
private var contentHeight = 0
private var isfirst = true
private var statusBarHeight = 0
private var needStatusBar = true
init {
try {
//获取状态栏的高度
val resourceId = activity.resources.getIdentifier("status_bar_height", "dimen", "android")
statusBarHeight = activity.resources.getDimensionPixelSize(resourceId)
val content = activity.findViewById<FrameLayout>(R.id.content)
mChildOfContent = content.getChildAt(0)
needStatusBar = needStatusBars
//界面出现变动都会调用这个监听事件
mChildOfContent?.let {
it.getViewTreeObserver().addOnGlobalLayoutListener {
if (isfirst) {
contentHeight = it.height //兼容华为等机型
isfirst = false
}
if (activity.isDestroyed || activity.isFinishing) return@addOnGlobalLayoutListener
possiblyResizeChildOfContent()
}
frameLayoutParams = it.layoutParams as FrameLayout.LayoutParams
}
} catch (e: Exception) {
e.printStackTrace()
}
}
//重新调整跟布局的高度
private fun possiblyResizeChildOfContent() {
val usableHeightNow = computeUsableHeight()
//当前可见高度和上一次可见高度不一致 布局变动
if (usableHeightNow != usableHeightPrevious) {
//int usableHeightSansKeyboard2 = mChildOfContent.getHeight();//兼容华为等机型
val usableHeightSansKeyboard = (mChildOfContent?.rootView?.height) ?: 0
val heightDifference = usableHeightSansKeyboard - usableHeightNow
var height = contentHeight
height = if (heightDifference > usableHeightSansKeyboard / 4) {
// keyboard probably just became visible
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//frameLayoutParams.height = usableHeightSansKeyboard - heightDifference;
usableHeightSansKeyboard - heightDifference + if (!needStatusBar) 0 else statusBarHeight
} else {
usableHeightSansKeyboard - heightDifference
}
} else {
contentHeight
}
YzLog.e("possiblyResizeChildOfContent========height=$height usableHeightNow=$usableHeightNow usableHeightSansKeyboard=$usableHeightSansKeyboard")
// if (height>1080){
frameLayoutParams?.height = height
mChildOfContent?.requestLayout()
// }
usableHeightPrevious = usableHeightNow
}
}
/**
* 计算mChildOfContent可见高度
*/
private fun computeUsableHeight(): Int {
val r = Rect()
mChildOfContent!!.getWindowVisibleDisplayFrame(r)
return r.bottom - r.top
}
companion object {
fun assistActivity(activity: Activity?, needStatusBar: Boolean) {
if (activity == null || activity.isDestroyed || activity.isFinishing) return
AndroidBug5497Workaround(activity, needStatusBar)
}
fun assistActivity(activity: Activity?) {
if (activity == null || activity.isDestroyed || activity.isFinishing) return
AndroidBug5497Workaround(activity, true)
}
}
}