Skip to content

Android 15+ 状态栏颜色设置

关键变更
在 Android 15(API 35+)中直接设置的状态栏颜色方法 window.statusBarColor 已被废弃。

问题背景

在 Android 14 及以下版本中,开发人员可通过简单代码设置状态栏颜色:

kotlin
// Android 14 及以下版本有效
window.statusBarColor = Color.RED

但在 Android 15 及以上版本中,这种方法:

  1. 已被标记为弃用
  2. 实际效果无效(状态栏保持默认透明或主题色)
  3. Android Studio 建议使用 WindowInsets API来设置状态栏背景

推荐方案:使用 WindowInsets API

核心实现(Kotlin)

kotlin
fun setStatusBarColor(window: Window, @ColorInt color: Int) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
        window.decorView.setOnApplyWindowInsetsListener { view, insets ->
            // 获取状态栏高度
            val statusBarInsets = insets.getInsets(WindowInsets.Type.statusBars())
            
            // 设置状态栏背景色
            view.setBackgroundColor(color)
            
            // 添加顶部padding防止内容重叠
            view.setPadding(0, statusBarInsets.top, 0, 0)
            
            insets // 返回原始insets
        }
    } else {
        // Android 14及以下版本兼容方案
        window.statusBarColor = color
    }
}

使用说明

  1. Activity.onCreate() 中调用:

    kotlin
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        setStatusBarColor(window, Color.RED) // 设置状态栏为红色
    }
  2. 必须开启边缘到边缘(Edge-to-Edge)布局:

    kotlin
    // 在 onCreate() 中调用(Android 21+ 需要)
    enableEdgeToEdge()

工作原理

  1. window.decorView 是整个窗口的根视图
  2. OnApplyWindowInsetsListener 会在系统栏尺寸确定后被调用
  3. getInsets(WindowInsets.Type.statusBar()) 获取状态栏高度
  4. 设置 setBackgroundColor 并添加顶部内边距,使内容不会与状态栏重叠

Jetpack Compose 实现方案

kotlin
@Composable
fun StatusBarColorBox(color: Color) {
    // 获取状态栏高度
    val statusBarHeight = WindowInsets.statusBars.getTop(LocalDensity.current)
    
    // 创建状态栏大小的Spacer并设置背景色
    Spacer(
        modifier = Modifier
            .height(statusBarHeight)
            .fillMaxWidth()
            .background(color)
    )
}

// 在Activity中的使用
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        enableEdgeToEdge()
        setContent {
            Box(Modifier.fillMaxSize()) {
                // 应用内容
                Content()
                
                // 顶部状态栏颜色设置
                StatusBarColorBox(Color.Red)
            }
        }
    }
}

@Composable
fun Content() {
    // 应用主要内容
}

必须调用

在调用此代码前确保启用边缘到边缘模式:

kotlin
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge() // 关键设置
    // ...其他代码...
}

过渡方案(将废弃)

通过主题声明临时恢复旧行为

xml
<!-- res/values-v35/themes.xml -->
<style name="Theme.MyApp" parent="Theme.Material3.DayNight">
    <item name="android:windowOptOutEdgeToEdgeEnforcement">true</item>
    <item name="android:statusBarColor">@color/status_bar_color</item>
</style>

注意事项

  1. 本方法为临时解决方案
  2. windowOptOutEdgeToEdgeEnforcement 属性
    • 在后续Android版本中将被移除
    • Google官方明确标记为未来会废弃
  3. 仅建议在迁移过程中短期使用

问题排查指南

症状原因解决方案
状态栏颜色无变化未启用 enableEdgeToEdge()onCreate() 中优先调用此方法
与系统UI重叠应用内容区域未避开状态栏添加 view.setPadding(0, statusBarInsets.top, 0, 0)
Android 14颜色失效未区分版本处理加入SDK版本检查逻辑
折叠屏显示异常未处理所有systemBar类型同时处理显示屏切口:WindowInsets.Type.statusBars() or Type.displayCutout()

设计规范建议

  1. 避免纯黑/纯白背景

    • 使用带轻微饱和度(#F44336 而非 #FF0000)
    • 提高与系统图标的对比度
  2. 动态暗/亮模式适配

kotlin
val isDarkMode = resources.configuration.uiMode and 
                 Configuration.UI_MODE_NIGHT_MASK == UI_MODE_NIGHT_YES

val statusBarColor = if(isDarkMode) {
    ColorUtils.setAlphaComponent(Color.DKGRAY, 220)
} else {
    ColorUtils.blendARGB(Color.WHITE, Color.LTGRAY, 0.2f)
}
  1. 动画过渡处理
kotlin
ViewCompat.setWindowInsetsAnimationCallback(rootView,
    object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
        override fun onProgress(
            insets: WindowInsetsCompat,
            runningAnimations: MutableList<WindowInsetsAnimationCompat>
        ): WindowInsetsCompat {
            // 更新状态栏色值过渡
            val fraction = runningAnimations[0].interpolatedFraction
            val newColor = evaluateColorTransition(startColor, endColor, fraction)
            statusBarBackground.color = newColor
            return insets
        }
    }
)

最佳实践

优先使用 WindowInsetsControllerCompat 代替直接操作视图组件,确保兼容不同API版本:

kotlin
WindowCompat.setDecorFitsSystemWindows(window, false)
WindowInsetsControllerCompat(window, window.decorView).apply {
    // 同时设置状态栏和导航栏
    systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BY_SWIPE
}