Android 15+ 状态栏颜色设置
关键变更
在 Android 15(API 35+)中直接设置的状态栏颜色方法window.statusBarColor
已被废弃。
问题背景
在 Android 14 及以下版本中,开发人员可通过简单代码设置状态栏颜色:
kotlin
// Android 14 及以下版本有效
window.statusBarColor = Color.RED
但在 Android 15 及以上版本中,这种方法:
- 已被标记为弃用
- 实际效果无效(状态栏保持默认透明或主题色)
- 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
}
}
使用说明
在
Activity.onCreate()
中调用:kotlinoverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) setStatusBarColor(window, Color.RED) // 设置状态栏为红色 }
必须开启边缘到边缘(Edge-to-Edge)布局:
kotlin// 在 onCreate() 中调用(Android 21+ 需要) enableEdgeToEdge()
工作原理
window.decorView
是整个窗口的根视图OnApplyWindowInsetsListener
会在系统栏尺寸确定后被调用getInsets(WindowInsets.Type.statusBar())
获取状态栏高度- 设置
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>
注意事项
- 本方法为临时解决方案
windowOptOutEdgeToEdgeEnforcement
属性- 在后续Android版本中将被移除
- Google官方明确标记为未来会废弃
- 仅建议在迁移过程中短期使用
问题排查指南
症状 | 原因 | 解决方案 |
---|---|---|
状态栏颜色无变化 | 未启用 enableEdgeToEdge() | 在 onCreate() 中优先调用此方法 |
与系统UI重叠 | 应用内容区域未避开状态栏 | 添加 view.setPadding(0, statusBarInsets.top, 0, 0) |
Android 14颜色失效 | 未区分版本处理 | 加入SDK版本检查逻辑 |
折叠屏显示异常 | 未处理所有systemBar类型 | 同时处理显示屏切口:WindowInsets.Type.statusBars() or Type.displayCutout() |
设计规范建议
避免纯黑/纯白背景
- 使用带轻微饱和度(#F44336 而非 #FF0000)
- 提高与系统图标的对比度
动态暗/亮模式适配
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)
}
- 动画过渡处理
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
}