Android 沉浸式(Edge-to-Edge)的介绍与应用

沉浸式是应用界面开发的不可避免要考虑的内容,在早期的 Android 应用中,屏幕的顶部是状态栏,底部是导航栏,而 APP 内容则被夹在中间,这种「三明治」式的布局结构长期主导 Android 设备的屏幕设计。

不过这种"非沉浸式"设计,在 2024 年以后的 Android 生态里,正在逐渐被淘汰。Google 从 Android 15 开始,强制所有 App 启用 Edge-to-Edge(边缘到边缘)。也就是说,你的内容必须延伸到状态栏和导航栏的后面,否则在新系统上会出现诡异的空白或黑边。

在 Android 14(API 级别 34)及更低版本中,应用的界面默认不会绘制在系统栏和刘海屏下方。

在 Android 15(API 级别 35)及更高版本中,如果您的应用以 SDK 35 为目标平台,则会在系统栏和刘海屏下方进行绘制。这样可带来更流畅的用户体验,并让您的应用充分利用可用的窗口空间。

沉浸式之前:Android 的三明治时代

在 Android 早期,系统栏(状态栏 + 导航栏)是 不透明且不可逾越 的。应用的 Activity 内容区域,默认就是从状态栏下方开始,到导航栏上方结束。开发者通常无需主动处理状态栏和导航栏的避让,不需要写任何代码,内容自然就在"安全区域"里。不过在 View 体系中,系统也提供了 fitSystemWindows 机制,用于让 View 自动适配系统窗口区域。

此时还可以通过主题色来控制系统栏颜色:

xml 复制代码
<!-- res/values/styles.xml -->
<style name="AppTheme" parent="Theme.MaterialComponents.DayNight.NoActionBar">
    <!-- 状态栏颜色 -->
    <item name="android:statusBarColor">@color/red</item>
    <!-- 导航栏颜色 -->
    <item name="android:navigationBarColor">@color/blue</item>
    <!-- 状态栏文字颜色(浅色/深色) -->
    <item name="android:windowLightStatusBar">true</item>
</style>

这就是"沉浸式之前"的完整方案:系统栏不透明 + 自定义颜色 + 内容自动避让

沉浸式的引入:Edge-to-Edge

Edge-to-Edge(边缘到边缘) 指的是 App 内容从屏幕的最左边缘延伸到最右边缘,从最上边缘延伸到最下边缘。系统栏(状态栏、导航栏)变成半透明或全透明,浮在你的内容上方。

而其最关键的 API 就是 enableEdgeToEdge(),它是 androidx.activity:activity 1.8.0 引入的扩展函数。这个方法做了以下三件事:

  • 将状态栏和导航栏设置为透明
  • 允许你的内容绘制到系统栏区域后面
  • 自动处理亮色/暗色主题下系统栏图标的颜色(浅色/深色)

也就是说,在调用 enableEdgeToEdge() 之后,应用内容就从原来的三明治结构,延伸到系统栏的后面,这种沉浸式带来的视觉体验的提升是显著的。不过对于开发者来说,就必须手动处理边缘的避开逻辑,以免内容被系统栏遮挡。

例如,使用如下的代码开启沉浸式,你就可以在状态栏之下显示应用内容:

kotlin 复制代码
// 在 Activity.onCreate() 中调用
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    enableEdgeToEdge()  					// ← 启用沉浸式
    setContentView(R.layout.activity_main)
}

虽然说需要调用 enableEdgeToEdge() 方法才能进入沉浸式,但从 Android 15(targetSDK >=35)开始,即使不调用此方法,也会自动启用 Edge-to-Edge。

另外这里再提一句,Edge-to-Edge 的本质 API 是 WindowCompat.setDecorFitsSystemWindows(window, false)androidx.activity 中的 enableEdgeToEdge() 只是 Jetpack 对这一行为的进一步封装,它会自动处理系统栏透明、图标颜色等问题。在开发中我们用后者就行。

沉浸式的适配:WindowInsets

对于沉浸式的适配,实际上就是对边缘区域的留白,以避免应用的内容被压在状态栏之下。这里就不得不提到 WindowInsets 这个类了。这个类就是告诉你,屏幕的上下左右的边缘有多少像素被系统占用了,你的内容需要避开多少。

例如:

kotlin 复制代码
val rootView = findViewById<View>(android.R.id.content)
val windowInsets = ViewCompat.getRootWindowInsets(rootView)
if (windowInsets != null) {
    val systemBars = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
    // 示例返回:Insets { left=0, top=74, right=0, bottom=126 }
}

这些值不是坐标,不是系统栏高度,而是你的内容需要往内缩多少像素才能不被挡住:

  • top = 74 → 内容从第 74 像素开始,才不会被状态栏遮挡
  • bottom = 126 → 内容在第 126 像素之前结束,才不会被导航栏遮挡

上面只用到了 systemBars 这个类型,但是在 WindowInsetsCompat.Type 中系统还提供了很多系统 UI 类型供开发者查询:

Type 含义 典型返回值
statusBars() 状态栏 top=74, 其余=0
navigationBars() 导航栏 bottom=126, 其余=0
systemBars() 上面两个的并集 top=74, bottom=126
ime() 软键盘 收起时 bottom=0,弹出时 bottom=键盘高度
displayCutout() 刘海屏/挖孔屏 刘海区域 top=额外高度
systemGestures() 系统手势区域 左右边缘及底部有预留区域,用于避免系统手势冲突

这里要注意,上述表格中的返回值因设备而异,不一定相同。

获取和设置 Inset

在传统的 View 体系中,可以通过如下方式来获取并设置 Inset:

kotlin 复制代码
// Activity 中
enableEdgeToEdge()
// 在根 View 上监听 insets
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    // 手动设置 padding,让内容避开系统栏
    view.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
    insets  	// 返回 insets,让后续 View 也能收到
}

而在 Compose 中,系统提供了开箱即用的 Modifier:

kotlin 复制代码
// 同时避开状态栏和导航栏
Modifier.systemBarsPadding()
// 只避开状态栏
Modifier.statusBarsPadding()
// 只避开导航栏
Modifier.navigationBarsPadding()
// 避开软键盘
Modifier.imePadding()
// 组合多种 insets
Modifier.windowInsetsPadding(
    WindowInsets.systemBars.union(WindowInsets.ime)
)
相关推荐
恋猫de小郭1 小时前
AndroidX 将引入有全新 AppState ,用于管理 Compose 状态
android·前端·flutter
Zender Han1 小时前
Flutter 轻量存储方案介绍、区别、对比和使用场景
android·flutter·ios
黄林晴1 小时前
Google Play 强制截止,内购应用必须升级 Billing 8,不改无法更新
android
zhangphil1 小时前
Android RecyclerView+Coil解码Bitmap设置进View,RenderThread上屏显示Graphics
android
idingzhi1 小时前
A股量化策略日报(2026年05月11日)
android·开发语言·python·kotlin
我命由我123451 小时前
Jetpack Compose - 设置 Compose 编译器、设置 Compose 依赖项
android·java·java-ee·kotlin·android jetpack·android-studio·android runtime
Kapaseker2 小时前
reified 如何骗过 JVM 类型擦除
android·kotlin
硬件学长森哥2 小时前
成像技术系列-3A算法基础
android·图像处理·计算机视觉
唔662 小时前
Android在局域网中搭建 MQTT服务器 协议V3.1.1
android·运维·服务器