常见零碎栏需要

对于零碎栏(这里指状态栏和导航栏),常见有如下需要

  1. 设置零碎栏色彩
  2. 实现全透明/半透明的零碎栏 - 使零碎栏笼罩在利用内容上
  3. 确保零碎栏上图标文字的可读性

    • 浅色模式(light),白底黑字
    • 深色模式(dark),黑底白字
  4. 沉迷式 - 暗藏零碎栏,但可通过交互从新显示,有三种交互模式:

    • 触摸屏幕显示
    • 滑过屏幕边缘显示
    • 滑过屏幕边缘显示并在数秒后从新暗藏

设置零碎栏色彩

  • API21+ 可用
  • WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS 必须被设置,默认是已设置的
    此标记指定由该利用窗口负责绘制零碎栏区域的背景,同时零碎栏窗口会将背景设置为全透明
    未设置此标记时零碎栏会将窗口背景设置为彩色
// 设置状态栏色彩 window.statusBarColor = color// 设置导航栏色彩 window.navigationBarColor = color// API28+能够设置导航栏分隔线色彩window.navigationBarDividerColor = color

实现全透明/半透明的零碎栏

使零碎栏笼罩在利用内容上,再设置零碎栏色彩就能够实现 全透明/半透明 的零碎栏

  • API16+ 可用
window.decorView.apply {    // 设置状态栏零碎栏笼罩在利用内容上    systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN         // 设置导航栏零碎栏笼罩在利用内容上     systemUiVisibility = systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION } 

注:设置SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 只会对状态栏失效,但设置了 SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 却同时对状态栏和导航栏失效,但文档上却没说,不晓得是否兼容性问题

  • API30+ 提供了新的API,View.SYSTEM_UI_FLAG_LAYOUT_*标记为废除了
// 当设置为true时,框架还是会旧用的API来解决// 当设置为false时,状态栏与导航栏会笼罩在利用内容上,无奈别离设置void setDecorFitsSystemWindows(boolean decorFitsSystemWindows)

API19+ 应用以下标记也能够实现全透明零碎栏,但 API30+ 曾经标记废除,倡议不要应用

  • WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS
    设置后零碎主动增加 View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
  • WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION
    设置后零碎主动增加 View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION

确保零碎栏上图标文字的可读性

在设置了通明零碎栏时,零碎栏笼罩在利用内容上
如果零碎栏上的图标文字与利用内容对比度不够,那就看不清零碎栏图标文字了

在 API23+ 可设置状态栏浅色模式
在 API26+ 可设置导航栏浅色模式

window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BARwindow.decorView.systemUiVisibility = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR

在 API29+,当零碎栏色彩为0(通明)时,可设置是否由零碎栏窗口绘制一个半透明的背景来提供对比度

  • 当零碎栏在浅色模式时,绘制红色的半透明背景,彩色的图标文字
  • 当零碎栏在深色模式时,绘制彩色的半透明背景,红色的图标文字
// 状态栏默认falsewindow.isStatusBarContrastEnforced = false// 导航栏默认truewindow.isNavigationBarContrastEnforced = true

零碎栏惯例操作

总结一下,能够发现零碎栏有如下基本操作,可组合应用

  • 设置零碎栏背景色
  • 设置笼罩在利用内容上
  • 设置零碎栏浅色模式
  • 设置是否在零碎纺栏色彩为0时,显示默认的零碎栏半透明背景

定义如下接口,能够不便地批改零碎栏状态

interface Bar {     // 设置零碎栏背景色    fun color(@ColorInt color: Int): Bar    // 设置笼罩在利用内容上    fun overlay(value: Boolean = true): Bar        // 设置零碎栏浅色模式    fun light(value: Boolean = true): Bar    // 设置是否在零碎纺栏色彩为0时,显示默认的零碎栏半透明背景    fun contrast(value: Boolean = true): Bar}

提供扩大函数

fun Activity.systemBars(): Bar = SystemBars(window)fun Fragment.systemBars(): Bar = SystemBars(requireActivity().window)fun Dialog.systemBars(): Bar = SystemBars(window!!)fun Activity.statusBar(): Bar = StatusBar(window)fun Fragment.statusBar(): Bar = StatusBar(requireActivity().window)fun Dialog.statusBar(): Bar = StatusBar(window!!)fun Activity.navigationBar(): Bar = NavigationBar(window)fun Fragment.navigationBar(): Bar = NavigationBar(requireActivity().window)fun Dialog.navigationBar(): Bar = NavigationBar(window!!)var Window.isDrawsSystemBarBackgrounds: Booleanvar Window.isStatusBarOverlay: Booleanvar Window.isStatusBarLight: Booleanvar Window.isNavigationBarOverlay: Boolean var Window.isNavigationBarLight: Boolean

应用

// 设置全透明零碎栏statusBar().overlay().color(Color.TRANSPARENT)// 设置半透明零碎栏statusBar().overlay().color(0x66ff0000) 

在沉迷式模式下,操作 color/light/contrast 有效

沉迷式

安卓零碎提供了三种沉迷式模式,它们都会暗藏零碎栏

  • 向后歪斜模式 - 触摸屏幕从新显示零碎栏
  • 沉迷模式 - 滑过屏幕边缘从新显示零碎栏
  • 粘性沉迷模式 - 滑过屏幕边缘从新显示零碎栏并在数秒后从新暗藏,此形式无奈收到零碎栏的可见性变动事件
fun Window.immersive(enable: Boolean = true, swipe: Boolean = false, transientBars: Boolean = false) {    // 在暗藏/显示零碎栏时,不心愿布局随之扭转    WindowCompat.setDecorFitsSystemWindows(this, !enable)    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {        if (enable) {            // 从新显示的形式            insetsController?.systemBarsBehavior = when {                swipe && transientBars -> WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE                swipe -> WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE                else -> WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_TOUCH            }            // 暗藏零碎栏            insetsController?.hide(WindowInsets.Type.systemBars())        } else {            // 退出沉迷式            insetsController?.show(WindowInsets.Type.systemBars())        }    } else {        // 暗藏零碎栏        val flags = View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION        val immersiveFlags = when {            // 退出沉迷式            !enable -> View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or View.SYSTEM_UI_FLAG_IMMERSIVE            // 从新显示的形式            swipe && transientBars -> View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY            swipe -> View.SYSTEM_UI_FLAG_IMMERSIVE            else -> 0        }        setSystemUiVisibility(flags or immersiveFlags, enable)    }}

工具库

https://github.com/czy1121/sy...

DEMO APK 下载: https://github.com/czy1121/sy...

repositories {     maven { url "https://gitee.com/ezy/repo/raw/android_public/"}} dependencies {    implementation "me.reezy.jetpack:systembars:0.4.0" }