Skip to content

Android状态栏与边缘到边缘适配

问题描述

在Android 15(API 35)中,系统默认启用了**边缘到边缘(Edge-to-Edge)**显示模式。这种更改导致应用内容会延伸到状态栏和导航栏区域,这解释了为何UI元素会出现在状态栏后方:

xml
<!-- 传统布局(Android 15前) -->
<CoordinatorLayout
    android:fitsSystemWindows="true"
    ... >

启用了fitsSystemWindows的显示效果

当尝试通过ViewCompat.setOnApplyWindowInsetsListener手动处理系统栏插入时,出现了状态栏和AppBarLayout颜色不一致的问题:

kotlin
ViewCompat.setOnApplyWindowInsetsListener(rootView) { v, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
    insets
}

手动处理insets时的显示问题

核心概念解析

边缘到边缘的必要性

  1. 视觉连续性:消除系统栏与应用内容的割裂感
  2. 沉浸式体验:最大化利用屏幕显示区域
  3. Android 15+强制要求:新应用的默认行为,提供更现代的设计语言

潜在副作用

  • 内容遮挡:界面元素可能被系统栏覆盖
  • 高度计算错误:getHeight()返回包含系统栏区域的值
  • 触摸冲突:底部交互区域与导航栏重叠

解决方案

方案1:为AppBar添加状态栏内边距(推荐)

kotlin
ViewCompat.setOnApplyWindowInsetsListener(
    findViewById(R.id.appbar)
) { v: View, insets: WindowInsetsCompat ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    v.updatePadding(top = systemBars.top)
    insets
}

关键修改:

  1. 仅监听AppBarLayout而不是根布局
  2. 只设置顶部内边距(保留原有侧边内边距)

方案2:统一系统栏与AppBar颜色

kotlin
// 在Activity的onCreate中调用
window.statusBarColor = Color.TRANSPARENT
findViewById<AppBarLayout>(R.id.appbar).setBackgroundColor(ContextCompat.getColor(this, R.color.primary))

亮/暗模式适配

kotlin
WindowCompat.getInsetsController(window, window.decorView).apply {
    // 亮色状态栏图标(深色背景)
    isAppearanceLightStatusBars = !isDarkTheme
    
    // 暗色状态栏图标(浅色背景)
    // isAppearanceLightStatusBars = isLightTheme
}

版本兼容处理(Android 8+)

kotlin
// 启用边缘到边缘
EdgeToEdge.enable(this)

// 处理底部导航栏重叠
ViewCompat.setOnApplyWindowInsetsListener(bottomActionBar) { v, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    v.updatePadding(bottom = systemBars.bottom)
    insets
}

布局文件优化

xml
<com.google.android.material.appbar.AppBarLayout
    android:id="@+id/appbar"
    android:fitsSystemWindows="false"
    ... >
    
    <androidx.appcompat.widget.Toolbar
        app:contentInsetStart="0dp"
        app:contentInsetLeft="0dp" />
</com.google.android.material.appbar.AppBarLayout>

Android 15+专用适配

kotlin
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
    window.insetsController?.let {
        // 完全隐藏系统栏
        it.hide(WindowInsets.Type.systemBars())
        
        // 始终显示状态栏图标
        it.setSystemBarsAppearance(
            WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS,
            WindowInsetsController.APPEARANCE_LIGHT_STATUS_BARS
        )
    }
}

常见问题解决

1. 状态栏颜色设置无效

原因:Android 15+使用动态着色机制
解决方案

kotlin
window.statusBarColor = Color.TRANSPARENT
WindowCompat.setDecorFitsSystemWindows(window, false)

2. 初始化时无法获取WindowInsets

解决方案:添加布局附着监听器

kotlin
fun View.listenForInsets() {
    if (rootWindowInsets != null) {
        applyWindowInsets(rootWindowInsets)
        return
    }
    
    addOnAttachStateChangeListener(object : View.OnAttachStateChangeListener {
        override fun onViewAttachedToWindow(v: View) {
            v.removeOnAttachStateChangeListener(this)
            applyWindowInsets(v.rootWindowInsets)
        }
        
        override fun onViewDetachedFromWindow(v: View) {}
    })
}

3. 全面屏设备适配

kotlin
// 在Activity中
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
    window.attributes.layoutInDisplayCutoutMode = 
        WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}

最佳实践建议

  1. 始终使用WindowInsetsCompat替代直接系统API调用
  2. 测试时覆盖API 26+的设备(包含首批全面屏设备)
  3. Theme.Xml中预设状态栏颜色:
xml
<style name="Theme.MyApp" parent="Theme.Material3.DayNight">
    <item name="android:statusBarColor">@android:color/transparent</item>
    <item name="android:navigationBarColor">@android:color/transparent</item>
</style>

重要提醒

禁用fitsSystemWindows时,需手动处理所有系统栏重叠:顶部状态栏和底部导航栏都需要单独设置内边距/外边距

总结

边缘到边缘设计在Android 15+已成为强制标准。核心解决思路:

  1. 通过WindowCompat.setDecorFitsSystemWindows(window, false)启用边缘到边缘
  2. 为不同系统栏区域单独设置内边距
  3. 使用WindowInsetsController管理状态栏图标样式
  4. 采用透明系统栏结合应用自主着色方案

完整实现可参考Android官方文档中的边缘到边缘示例,其中包含Java和Kotlin的详细实现代码。