前言
在Android11后,google推出了WindowInsetsController 來取代之前復雜麻煩的窗口控制. 意在將Android的窗口控制更簡單. 這里說明下什么是窗口控制,在Android手機里,狀態欄,導航欄.輸入法等等這些與app無關,但是需要配合app一起使用的窗口部件.
另外注意WindowInsetsController需要Android 11 (R) API 30 才能使用, google提供了ViewCompat作為向下的兼容.
添加依賴
implementation 'androidx.core:core:1.6.0'
隱藏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