Android全屏模式下,即使设置windowSoftInputMode为adjustResize,键盘未推移Activity导致无法生效

问题

当输入框处于最底部时

当我们点击输入框,唤起软键盘,会挡住我们的输入框内容 如图

解决方案 1 设置 android:windowSoftInputMode="adjustResize"

这种方式会把页面整体上推 可以看到头部标题整体向上平移了 虽然也能解决问题 但是ui上不友好

解决方案 2 android:windowSoftInputMode="adjustResize" + ScrollView

当时要满足两种情况下才会生效

  1. 需要界面本身可调整尺寸
  2. 页面不是全屏时
我们项目中 满足条件1 我们在布局外层包裹NestedScrollView 但是我们是全屏的布局 这就导致第二个条件不满足 所以得寻求解决方案 这样就衍生出了 AndroidBug5497Workaround

既在非全屏模式(即状态栏不透明)下,将activitywindowSoftInputMode的属性设置为:adjustResize。同时在ViewonSizeChanged(int w, int h, int oldw, int oldh)里可以得到变化后的尺寸,然后根据前后变化的结果来计算屏幕需要移动的距离。

但是在全屏模式下,即使将activitywindowSoftInputMode的属性设置为:adjustResize。 在键盘显示时它未将Activity的Screen向上推动,所以你Activityview的根树的尺寸是没有变化的。 在这种情况下,你也就无法得知键盘的尺寸,对根view的作相应的推移。 全屏下的键盘无法Resize的问题从2.1就已经存在了,直到现在google还未给予解决。

终极解决方案 封装好了 上面有详细的备注

  1. 找到Activity的最外层布局控件,我们知道所有的Activity都是DecorView,它就是一个FrameLayout控件,该控件id是系统写死叫R.id.content,就是我们setContentView时,把相应的View放在此FrameLayout控件里 2.给我们的Activity的xml布局View设置一个Listener监听 View.getViewTreeObserver()可以获取一个ViewTreeObserver对象------它是一个观察者,用以监听当前View树所发生的变化。这里所注册的addOnGlobalLayoutListener,就是会在当前的View树的全局布局(GlobalLayout)发生变化、或者其中的View可视状态有变化时,进行通知回调。『软键盘弹出/隐 』都能监听到

  2. 获取当前界面可用高度

  3. 重设高度, 我们计算出的可用高度,是目前在视觉效果上能看到的界面高度。但当前界面的实际高度是比可用高度要多出一个软键盘的距离的。 注意:如果既使用了沉浸式状态栏,又加了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)
        }
    }
}
相关推荐
问道飞鱼1 分钟前
【移动端知识】移动端多 WebView 互访方案:Android、iOS 与鸿蒙实现
android·ios·harmonyos·多webview互访
aningxiaoxixi43 分钟前
Android 之 audiotrack
android
枷锁—sha1 小时前
【DVWA系列】——CSRF——Medium详细教程
android·服务器·前端·web安全·网络安全·csrf
Cao_Shixin攻城狮4 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter
呼啦啦呼啦啦啦啦啦啦7 小时前
利用pdfjs实现的pdf预览简单demo(包含翻页功能)
android·javascript·pdf
idjl9 小时前
Mysql测试题
android·adb
游戏开发爱好者811 小时前
iOS App 电池消耗管理与优化 提升用户体验的完整指南
android·ios·小程序·https·uni-app·iphone·webview
人生游戏牛马NPC1号12 小时前
学习 Flutter (四):玩安卓项目实战 - 中
android·学习·flutter
星辰也为你祝福h13 小时前
Android原生Dialog
android
梁同学与Android14 小时前
Android ---【CPU优化】需要优化的原因及优化的地方
android