Android:使用ViewCompat适配软键盘弹出,解决软键盘遮挡布局问题

1,682 阅读3分钟

前言

正在开发中的应用登录与注册模块的按钮会被软键盘遮挡,我需要做下处理。

希望实现的效果为这样:

video.gif video.gif

方案一:使用ViewCompat.setWindowInsetsAnimationCallback + translationY 移动布局实现

首先贴一下实现代码

ViewCompat.setWindowInsetsAnimationCallback(root,object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {

                    override fun onProgress(
                        insets: WindowInsetsCompat,
                        runningAnimations: MutableList<WindowInsetsAnimationCompat>
                    ): WindowInsetsCompat {
                        val startBottom = root.height - btn.bottom
                        val endBottom =
                            insets.getInsets(WindowInsetsCompat.Type.ime()).bottom.toFloat()
                        root.translationY = if (endBottom >= startBottom) {
                            startBottom - endBottom
                        } else {
                            0F
                        }
                        return insets
                    }
                })

接下来解释一下代码

ViewCompat这个类为Android11新APIWindowInsetsAnimation可实现效果的向后兼容类 有关WindowInsetsAnimation类的介绍可查看谷歌官方账号发布的让您的软键盘动起来系列文章

setWindowInsetsAnimationCallback此方法用于设置软键盘弹出监听。其中参数rootViewBinding生成类.root是页面根布局,callback则是关键,实现其中的onProgress方法即可监听软键盘弹出。当软键盘弹出时,该方法将会被多次回调。这时使用其中的insest参数调用getInsets方法即可获取当前软键盘高度。

startBottom由于我并不希望软键盘弹出多少界面就往上移动多少,而是希望软键盘遮挡我的按钮多少界面往上移动多少。所以我首先得计算我的按钮距离界面底部的距离,使用root.height - btn.bottom即可得出我的按钮距离界面底部的距离。btn.bottom获取的是什么可参考细说 Android 控件体系中的view.getBottom()。

endBottom则为当前软键盘高度。

小结

  1. 该代码和给控件设置点击监听一样,在onCreate中调用注册就行了。
  2. 使用该方案当软键盘弹出时,整体布局在向上移动中会忽然往下闪动一下然后再正常向上移动,推测是我计算btn底部距离时少算了什么。加了个else = 0F就不闪了,由于最后我没有使用该方案,也就没去深究。 如果你想实现的效果是软键盘弹出多少输入框向上移动多少使用该方案则没问题,不会闪动。我试过了,很丝滑。
  3. 由于我布局移动的距离较短,当键盘弹出时向上移动动画还很丝滑。但当软键盘隐藏时,动画会很快,看上去就像整体布局闪动了一下就回到了原位一样,很难看。所以我最终没选择这个方案。

方案二:使用ViewCompat.setOnApplyWindowInsetsListener + view.animate().setDuration(duration).translationY(value)移动布局实现

依旧先贴一下实现代码

    ViewCompat.setOnApplyWindowInsetsListener(mBinding.root) { _, insets ->
        val imeBottom = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
        var to = imeBottom - (mBinding.root.height - mBinding.btnRegister.bottom).toFloat()
        to = if (it.to > 0) -to else 0F
        root.animate().setDuration(300).translationY(to)
        insets
    }

接下来解释一下代码

setOnApplyWindowInsetsListener此方法用于设置软键盘弹出监听,但不会在软键盘弹出时多次回调。只会在软键盘显示与隐藏完成回调。

imeBottom软键盘高度

to计算出的我希望布局移动的距离,由于Android的坐标系并不是我们通常印象中的XY轴,而是一个倒转的XY轴,具体依然参考细说 Android 控件体系。所以需要将to也反转一下。同时不处理小于0的数据。

root.animate().setDuration(300).translationY(to)这段代码将会生成一个可执行动画,时间为300毫秒,移动方式为平滑Y轴移动。

小结

使用该方案动画时间就可以由我们自己控制了,这样当键盘隐藏时就不会出现动画时间过短像闪动一下就回到了原位的问题。

结语

写这篇文的本意是想着谷歌官方号的让您的软键盘动起来系列第二篇适配软键盘弹出,写的有点晦涩搞的我研究了好久。同时谷歌官方号的那篇文章也没有说该怎样适配Android11之前的软键盘。我想着我掉了这么多头发死了这么多脑细胞,大伙就没必要和我一样这么费神了。

引用

让您的软键盘动起来

细说 Android 控件体系