【安卓】系统栏与沉浸式

常见系统栏需求

对于系统栏(这里指状态栏和导航栏),常见有如下需求

  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_BAR

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

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

  • 当系统栏在浅色模式时,绘制白色的半透明背景,黑色的图标文字
  • 当系统栏在深色模式时,绘制黑色的半透明背景,白色的图标文字

// 状态栏默认false

window.isStatusBarContrastEnforced = false

// 导航栏默认true

window.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: Boolean

var Window.isStatusBarOverlay: Boolean

var Window.isStatusBarLight: Boolean

var 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"

}

【安卓】系统栏与沉浸式

以上是 【安卓】系统栏与沉浸式 的全部内容, 来源链接: utcz.com/a/101519.html

回到顶部