API 30新特性:WindowInsetsController

13,193 阅读3分钟

前言

setSystemUIVisibilty相信大部分App开发者都比较熟悉,实现App沉浸式或者对状态栏、导航栏图标进行反色时,可以通过setSystemUIVisibilty传入对应的Flag进行实现。但是从Android API 30开始,setSystemUIVisibilty就不被推荐使用了: 可以看到google最新的API中注明,setSystemUIVisibilty不被推荐,请使用WindowInsetsController来替代。接下来本文就介绍一下如何使用WindowInsetsController进行替换原来setSystemUIVisibilty。

WindowInsetsController

WindowInsetsController是一个接口类,它主要作用就是控制窗口行为,此类在Android R(API 30)添加,意在简化原先代码动态修改窗口SystemBars(StatusBar&NavigationBar)表现。

相关参数介绍

  • APPEARANCE_LIGHT_NAVIGATION_BARS 控制NavigationBar(导航栏)反色的标志,相当于SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
  • APPEARANCE_LIGHT_STATUS_BARS 控制StatusBar(状态栏)反色的标志,相当于SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
  • BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE 设置后可以通过手势呼出半透明的SystemBars 上述的接口就是当前WindowInsetsController中定义的常量,还有两个常量BEHAVIOR_SHOW_BARS_BY_SWIPE和BEHAVIOR_SHOW_BARS_BY_TOUCH这里没有描述,是因为在即将到来的Android S(API 31)中,它们并不被推荐使用,它们都被归类到BEHAVIOR_DEFAULT中了。详情可以参考开发者doc:developer.android.com/reference/k…

App中实现

App中原先设置窗口反色和隐藏SystemBars的方式通常为两种,一是通过配置Activity Style进行,而是在Activity中通过设置DecorView的SystemUIVisibility属性进行配置。Google针对此变化,并没有给出相应的Sample Code,相信一定是与原来的用法差异不大。

传统方式实现

参考原先调用setSystemUIVisibilty的方式,我们可以这么来实现:

    fun initSystemBars() {
        var controller = window.decorView.windowInsetsController
        // 设置状态栏反色
        controller?.setSystemBarsAppearance(APPEARANCE_LIGHT_STATUS_BARS, APPEARANCE_LIGHT_STATUS_BARS)
        // 取消状态栏反色
        controller?.setSystemBarsAppearance(0, APPEARANCE_LIGHT_STATUS_BARS)
        // 设置导航栏反色
        controller?.setSystemBarsAppearance(APPEARANCE_LIGHT_NAVIGATION_BARS, APPEARANCE_LIGHT_NAVIGATION_BARS)
        // 取消导航栏反色
        controller?.setSystemBarsAppearance(0, APPEARANCE_LIGHT_NAVIGATION_BARS)
        // 同时设置状态栏和导航栏反色
        controller?.setSystemBarsAppearance((APPEARANCE_LIGHT_STATUS_BARS or APPEARANCE_LIGHT_NAVIGATION_BARS),
                (APPEARANCE_LIGHT_STATUS_BARS or APPEARANCE_LIGHT_NAVIGATION_BARS))
        // 同时取消状态栏和导航栏反色
        controller?.setSystemBarsAppearance(0, (APPEARANCE_LIGHT_STATUS_BARS or APPEARANCE_LIGHT_NAVIGATION_BARS))
        // 隐藏状态栏
        controller?.hide(WindowInsets.Type.statusBars())
        // 显示状态栏
        controller?.show(WindowInsets.Type.statusBars())
        // 隐藏导航栏
        controller?.hide(WindowInsets.Type.navigationBars())
        // 显示导航栏
        controller?.show(WindowInsets.Type.navigationBars())
        // 同时隐藏状态栏和导航栏
        controller?.hide(WindowInsets.Type.systemBars())
        // 同时隐藏状态栏和导航栏
        controller?.show(WindowInsets.Type.systemBars())
    }

在Activity中,你只需要获取到当前window的decorView即可按照自己的需求,控制窗口SystemBars的变化了。

使用AndroidX接口实现

当然,在AndroidX中,也提供了一种方式让用户快速获取WindowInsetsController,来设置窗口SystemBars的属性。首先你需要导入AndroidX core依赖:

    implementation 'androidx.core:core-ktx:1.5.0-beta02'

然后通过ViewCompat获取到WindowInsetsController即可进行操作了,代码如下:

    fun initSystemBarsByAndroidX() {
        var controller = ViewCompat.getWindowInsetsController(window.decorView)
        // 设置状态栏反色
        controller?.isAppearanceLightStatusBars = true
        // 取消状态栏反色
        controller?.isAppearanceLightStatusBars = false
        // 设置导航栏反色
        controller?.isAppearanceLightNavigationBars = true
        // 取消导航栏反色
        controller?.isAppearanceLightNavigationBars = false
        // 隐藏状态栏
        controller?.hide(WindowInsets.Type.statusBars())
        // 显示状态栏
        controller?.show(WindowInsets.Type.statusBars())
        // 隐藏导航栏
        controller?.hide(WindowInsets.Type.navigationBars())
        // 显示导航栏
        controller?.show(WindowInsets.Type.navigationBars())
        // 同时隐藏状态栏和导航栏
        controller?.hide(WindowInsets.Type.systemBars())
        // 同时隐藏状态栏和导航栏
        controller?.show(WindowInsets.Type.systemBars())
    }

TODO: 通过源码具体看下系统是如何处理新的窗口SystemUIAppearance属性的。

参考

developer.android.com/reference/a… developer.android.com/reference/k…