状态栏相关知识


设置状态栏文字颜色(黑/白)

设置为浅色状态栏,即黑色字体

private fun setLightStatusBar() {
	val flags = window.decorView.systemUiVisibility
	window.decorView.systemUiVisibility = flags or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}

设置为深色状态栏,即白色字体

private fun setDarkStatusBar() {
	val flags = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
	window.decorView.systemUiVisibility = flags xor View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
}

根据页面前景颜色动态改变状态栏图标颜色

Google提供了一个专门用于图像颜色提取和识别的库(Palette)。使用步骤:

1、引入依赖

dependencies {
    implementation 'androidx.palette:palette:1.0.0'
}

2、基本用法

val colorCount = 20
val left = 0
val top = 0
val right = getScreenWidth()
val bottom = getStatusBarHeight()
Palette
    .from(bitmap)
    .setRegion(left, top, right, bottom)
    .maximumColorCount(colorCount)
    .generate {
        it?.let { palette ->
			var mostPopularSwatch: Palette.Swatch? = null
            for (swatch in palette.swatches) {
				if (mostPopularSwatch == null
                    || swatch.population > mostPopularSwatch.population
                ) {
					mostPopularSwatch = swatch
                }
			}
			mostPopularSwatch?.let { swatch ->
				val luminance = ColorUtils.calculateLuminance(swatch.rgb)
                // If the luminance value is lower than 0.5, we consider it as dark.
                if (luminance < 0.5) {
                	setDarkStatusBar()
                } else {
					setLightStatusBar()
                }
			}
		}
}
  • from:方法需传一张bitmap图片,即Palette要解析的对象
  • setRegion:方法传入4个参数用于指定需要提取和解析的图像区域
  • maximumColorCount:告诉Palette一共需要提取多少个颜色特征点
  • generate:方法开始解析并将结果返回lambda表达式中

获取状态的宽度和高度

private fun getScreenWidth(): Int {
	return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
        windowManager.currentWindowMetrics.bounds.right
    } else {
        val displayMetrics = DisplayMetrics()
		windowManager.defaultDisplay.getMetrics(displayMetrics)
        displayMetrics.widthPixels
    }
}

private fun getStatusBarHeight(): Int {
	var result = 0
	val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
	if (resourceId > 0) {
		result = resources.getDimensionPixelSize(resourceId)
	}
	return result
}

沉浸式状态栏

所谓沉浸式状态栏就是将页面内容延伸到状态栏顶部,这样视觉效果更好, 我们需要在布局的根view添加”android:fitsSystemWindows”属性,同时我们的根布局必须使用”androidx.coordinatorlayout.widget.CoordinatorLayout” 控件。

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">

</androidx.coordinatorlayout.widget.CoordinatorLayout>

CoordinatorLayout的内部会根据fitsSystemWindows属性设置

setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)

这样CoordinatorLayout布局就能全屏显示了, 被CoordinatorLayout包含的子控件会自动偏移到状态栏一下, 如果我们需要子控件延伸到状态栏里面,需要将子控件用com.google.android.material.appbar.CollapsingToolbarLayout布局包含起来。

<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/root_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true">
    <com.google.android.material.appbar.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">
        <ImageView
            android:id="@+id/bg_image"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:fitsSystemWindows="true"
            />
    </com.google.android.material.appbar.CollapsingToolbarLayout>
    ...
</androidx.coordinatorlayout.widget.CoordinatorLayout>

隐藏底部导航栏,上滑显示

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    // Android R及以上使用windowInsetsController来控制状态栏和导航栏的状态,需要引用"androidx.core:core:1.5.0"及以上的依赖库
    val windowInsetsController = ViewCompat.getWindowInsetsController(window.decorView)
    windowInsetsController?.hide(WindowInsetsCompat.Type.navigationBars())
    windowInsetsController?.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
} else {
    // R以下设置systemUiVisibility value
    window.decorView.systemUiVisibility = window.decorView.systemUiVisibility or
            View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
            View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
}

  目录