Android開發 WindowInsetsController 窗口控制器


前言

  在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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM