关于沉浸式状态栏和导航栏适配问题

18 阅读1分钟

WindowCompact

windowCompact有三个方法

// 是否将内容布局超出状态栏
WindowCompat.setDecorFitsSystemWindows(Window, Boolean)

// 获取Insets控制器
WindowCompat.getInsetsController(Window, View)

// 是否能够将画面超出系统栏
WindowCompat.enableEdgeToEdge(Window)

沉浸式状态栏实现

fun Window.setTransparentStatusBar(isLight: Boolean) {
    WindowCompat.setDecorFitsSystemWindows(this, false)

    statusBarColor = Color.TRANSPARENT

    WindowCompat.getInsetsController(this, this.decorView).apply {
        isAppearanceLightStatusBars = isLight
    }
}

处理内容的偏移

fun View.handleContentPadding() {
    ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
        val systemWindow = insets.getInsets(
            WindowInsetsCompat.Type.systemBars() or
                    WindowInsetsCompat.Type.displayCutout())

        //为需要偏移的view设置padding
        v.setPadding(0,systemWindow.top,0,0)

        insets
    }
}

其中WindowInsetsCompat.Type 参数解释:

WindowInsetsCompat.Type.ime()//键盘
WindowInsetsCompat.Type.displayCutout()//刘海屏
WindowInsetsCompat.Type.statusBars()//状态栏
WindowInsetsCompat.Type.navigationBars()//导航栏
WindowInsetsCompat.Type.captionBar()//标题栏
WindowInsetsCompat.Type.systemBars()//状态栏,导航栏和标题栏
WindowInsetsCompat.Type.systemGestures()//系统手势
WindowInsetsCompat.Type.mandatorySystemGestures()//强制性系统手势
WindowInsetsCompat.Type.tappableElement()//可点击区域

顺带一提

看了下安卓新建项目时出现的方法,谷歌帮我们做了一些对系统栏的处理

fun ComponentActivity.enableEdgeToEdge(
    statusBarStyle: SystemBarStyle = SystemBarStyle.auto(Color.TRANSPARENT, Color.TRANSPARENT),
    navigationBarStyle: SystemBarStyle = SystemBarStyle.auto(DefaultLightScrim, DefaultDarkScrim),
) {
    val view = window.decorView
    val statusBarIsDark = statusBarStyle.detectDarkMode(view.resources)
    val navigationBarIsDark = navigationBarStyle.detectDarkMode(view.resources)
    val impl =
        Impl
            ?: (if (Build.VERSION.SDK_INT >= 35) {
                    EdgeToEdgeApi35()
                } else if (Build.VERSION.SDK_INT >= 30) {
                    EdgeToEdgeApi30()
                } else if (Build.VERSION.SDK_INT >= 29) {
                    EdgeToEdgeApi29()
                } else if (Build.VERSION.SDK_INT >= 28) {
                    EdgeToEdgeApi28()
                } else if (Build.VERSION.SDK_INT >= 26) {
                    EdgeToEdgeApi26()
                } else {
                    EdgeToEdgeApi23()
                })
                .also { Impl = it }
    impl.setUp(
        statusBarStyle,
        navigationBarStyle,
        window,
        view,
        statusBarIsDark,
        navigationBarIsDark,
    )
    impl.adjustLayoutInDisplayCutoutMode(window)
}

其中包含了沉浸状态栏,同时根据系统主题处理了状态栏的亮暗关系。所以可以直接使用这个方法。

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)

    enableEdgeToEdge()

    setContentView(R.layout.activity_main)
}

这样做之后可以保证我们的内容可以充满整个屏幕,至于说边距问题,直接添加padding就可以了。完整如下

class MainActivity : AppCompatActivity() {

    private lateinit var mBinding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        enableEdgeToEdge()

        mBinding = DataBindingUtil.setContentView(this, R.layout.activity_main)

        window.decorView.setPadding(
            window.decorView.paddingLeft,
            window.decorView.paddingTop,
            window.decorView.paddingRight,
            // 对导航栏进行padding
            window.decorView.paddingBottom + BarUtils.getNavBarHeight()
        )
    }

}