Android开发 WindowInsetsController 窗口控制器

前言

  在Android11后,google推出了WindowInsetsController 来取代之前复杂麻烦的窗口控制. 意在将Android的窗口控制更简单. 这里说明下什么是窗口控制,在Android手机里,状态栏,导航栏.输入法等等这些与app无关,但是需要配合app一起使用的窗口部件.

另外注意WindowInsetsController需要Android 11 (R) API 30 才能使用, google提供了ViewCompat作为向下的兼容.

 

隐藏or显示输入法

    private fun changeKeyboard(isShow: Boolean){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (isShow){
                window?.insetsController?.show(WindowInsets.Type.ime())
            } else{
                window?.insetsController?.hide(WindowInsets.Type.ime())
            }
        } else {
            ViewCompat.getWindowInsetsController(btn1).let { controller ->
                if (isShow){
                    controller?.show(WindowInsetsCompat.Type.ime())
                } else{
                    controller?.hide(WindowInsetsCompat.Type.ime())
                }
            }
        }
    }

监听输入法高度

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window.setDecorFitsSystemWindows(false)//这个一定要添加
            root.setWindowInsetsAnimationCallback(object : WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
                override fun onProgress(insets: WindowInsets, runningAnimations: MutableList<WindowInsetsAnimation>): WindowInsets {
                    val isVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
                    val keyboardHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
                    Log.e(TAG, "isVisible = $isVisible")
                    Log.e(TAG, "position = $keyboardHeight")
                    return insets
                }
            })
        } else {
            /*
             * 此兼容代码,并没有用,具体原因并不知道,但是上面的api30的代码还是正常的
             */
            ViewCompat.setOnApplyWindowInsetsListener(root) { v, insets ->
                val isVisible = insets.isVisible(WindowInsetsCompat.Type.ime())
                val keyboardHeight = insets.getInsets(WindowInsetsCompat.Type.ime()).bottom
                Log.e(TAG, "isVisible = $isVisible")
                Log.e(TAG, "keyboardHeight = $keyboardHeight")
                insets
            }
        }

隐藏or显示状态栏

    private fun changeStatusBars(isShow: Boolean){
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (isShow){
                window?.insetsController?.show(WindowInsets.Type.statusBars())
            } else{
                window?.insetsController?.hide(WindowInsets.Type.statusBars())
            }
        } else {
            ViewCompat.getWindowInsetsController(btn1).let { controller ->
                if (isShow){
                    controller?.show(WindowInsetsCompat.Type.statusBars())
                } else{
                    controller?.hide(WindowInsetsCompat.Type.statusBars())
                }
            }
        }
    }

让状态栏显示的操作方式

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            window?.insetsController?.hide(WindowInsets.Type.statusBars())
            /*
           * BEHAVIOR_SHOW_BARS_BY_TOUCH,  触摸显示状态栏 api31已经弃用
           * BEHAVIOR_SHOW_BARS_BY_SWIPE   滑动显示状态栏 api31已经弃用
           * BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 通过滑动短暂显示半透明状态栏(一般情况下推荐这个)
           */
            window?.insetsController?.systemBarsBehavior = WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE
        }

改变状态栏的文字颜色

只有2种选择,暗色与高亮

    /**
     * 改变状态栏文字颜色
     * 只有2种选择,白色与黑色
     */
    private fun changeStatusFountColor(isLight: Boolean) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            //android R (android 11, API 30) 使用下面的新api
            /*
             传入0则是清理状态,恢复高亮
             */
            val state = if (isLight) WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS else 0
            window?.insetsController?.setSystemBarsAppearance(state, WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS)
        } else {
            //低于android R 使用兼容模式
            ViewCompat.getWindowInsetsController(btn1).let { controller ->
                controller?.isAppearanceLightStatusBars = isLight
            }
        }
    }

隐藏or显示导航栏

    private fun changeNavigationBars(isShow: Boolean) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (isShow){
                window?.insetsController?.show(WindowInsets.Type.navigationBars())
            } else{
                window?.insetsController?.hide(WindowInsets.Type.navigationBars())
            }
        } else {
            ViewCompat.getWindowInsetsController(btn1).let { controller ->
                if (isShow){
                    controller?.show(WindowInsetsCompat.Type.navigationBars())
                } else{
                    controller?.hide(WindowInsetsCompat.Type.navigationBars())
                }
            }
        }
    }

隐藏or显示系统栏(其实就是导航栏+状态栏)

这种同时隐藏导航栏与状态栏的方式,时候在播放视频的时候使用

    private fun changeSystemStatus(isShow: Boolean) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            if (isShow){
                window?.insetsController?.show(WindowInsets.Type.systemBars())
            } else{
                window?.insetsController?.hide(WindowInsets.Type.systemBars())
            }
        } else {
            ViewCompat.getWindowInsetsController(btn1).let { controller ->
                if (isShow){
                    controller?.show(WindowInsetsCompat.Type.systemBars())
                } else{
                    controller?.hide(WindowInsetsCompat.Type.systemBars())
                }
            }
        }
    }

 

 

 

End

上一篇:Android端渗透测试环境——自测最优实践方案


下一篇:Appium工作原理