前言
在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