在 Wear OS 7 (API 37) 之前,平台不会在应用窗口上呈现系统状态栏,应用会占据整个屏幕,并且可以在顶部(12 点钟位置)绘制任何内容(例如应用内 TimeText 时钟、自定义弧形标题或顶部控件)。
从 Wear OS 8 开始,系统会在应用窗口上方 12 点钟位置渲染状态栏,以显示时间和状态指示器。此功能现已在 Wear OS 7.1 Beta 版预览模拟器 (API 37.2-beta1) 中提供,可供进行早期预览版测试。为避免与系统状态栏重叠,应用应停止渲染自己的时钟 (TimeText),并遵循顶部状态栏窗口边衬区(从 Wear Compose 1.8 开始,由 AppScaffold 和 ScreenScaffold 自动处理),或在需要全屏沉浸式体验时隐藏系统状态栏。
主要优势包括:
- 视觉一致性:在整个系统和所有应用中采用统一的时钟排版、位置和背板。
- 系统状态指示器:允许平台在各个界面上显示状态图标(例如活跃的麦克风和位置指示器、连接性状态或电池信息)和时间。系统会根据优先级,一次仅显示一个图标。
- 自动滚动和过渡协调:与 Jetpack Compose for Wear OS 1.8 搭配使用时,系统状态栏会在用户滚动浏览内容时自动隐藏,并在短暂(2 秒)闲置延迟后重新显示。
设置应用
首先,请完成以下前提条件步骤:
- 安装 Android Studio 预览版 (Canary)。
- 在 SDK 管理器中,下载 Wear OS 7.1 预览版模拟器系统映像 (API 37.2-beta1)。此版本让您可以在 Wear OS 8 SDK 发布之前抢先体验 Wear OS 8 系统状态栏。
- 在设备管理器中,使用 API 37.2-beta1 映像创建并启动 Wear OS 虚拟设备。
如需在应用中支持系统状态栏,请将应用的 targetSdk 版本更新为 35 或更高版本。平台仅会为搭载 API 35+ 的应用启用系统状态栏,以保持与旧版应用的向后兼容性。
此外,请将 Wear Compose 依赖项更新为最新的 Alpha 版本(目前为 1.8.0-alpha03),如以下代码段所示。如果您的应用使用的是旧版 Wear Compose,您可以使用 Wear Compose Material 3 迁移技能来协助迁移。
android {
defaultConfig {
targetSdk = 35
}
}
dependencies {
implementation("androidx.wear.compose:compose-foundation:1.8.0-alpha03")
implementation("androidx.wear.compose:compose-material3:1.8.0-alpha03")
}
使用系统状态栏
在最新 Alpha 版 Wear Compose Material 3 1.8.0(目前为 1.8.0-alpha03)中,该库会自动将 com.google.wear.ENABLE_GLOBAL_STATUS_BAR <meta-data> 属性合并到 AndroidManifest.xml 中,从而为您的应用启用该功能。在运行时,AppScaffold 和 ScreenScaffold 会检查设备上是否已启用系统状态栏,以及此清单选择启用属性是否设置为 true:
- 在预览版模拟器/Wear OS 8+(选择启用时)上:
AppScaffold会抑制其内部TimeText,以便系统状态栏在 12 点钟位置清晰呈现,而不会重复。ScreenScaffold会重新计算contentPadding,以将状态栏边衬边界考虑在内,并在列表滚动时协调隐藏和显示状态栏。 - 在 Wear OS 7 及更低版本的设备上(或未选择启用时):
AppScaffold会自动回退到渲染标准应用内TimeText,从而通过单个代码库保持完全向后兼容。
@Composable fun GsbSampleApp() { // AppScaffold coordinates the system status bar across the app // and falls back to rendering TimeText on Wear OS 7 and earlier. AppScaffold { val columnState = rememberTransformingLazyColumnState() // ScreenScaffold includes status bar top inset clearance in // contentPadding and hides/shows the status bar during list scrolling. ScreenScaffold(scrollState = columnState) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { item { ListHeader { Text("Hello Status Bar") } } items(count = 15) { index -> Button(onClick = { /* Handle click */ }) { Text("Item #${index + 1}") } } } } } }
运行示例时,您会看到以下内容:
- 静止(列表顶部):系统状态栏显示在 12 点钟位置。“Hello Status Bar”标题位于状态栏边衬区下方,没有剪裁或重叠。
- 向下滚动:当您滚动浏览列表项时,状态栏会隐藏,列表项会在顶部边框后面全屏滚动。
- 闲置:当您停止滚动并松开屏幕时,状态栏会在大约 2 秒后自动重新显示。
处理常见场景和自定义
以下部分介绍了如何处理使用系统状态栏时可能遇到的常见场景。
处理非滚动(静态)屏幕
在采用静态布局(例如 Column 或 Box)而非滚动列表的屏幕上,将 ScreenScaffold 提供的 contentPadding 应用于根布局,这样顶部的界面元素就不会与系统状态栏重叠:
AppScaffold { ScreenScaffold { contentPadding -> Column(modifier = Modifier.padding(contentPadding)) { Text("Static Screen Content") } } }
使用全屏互动组件
Wear Compose Material 3 中的全屏互动组件(包括 AlertDialog、Dialog、Stepper、TimePicker 和 DatePicker)在屏幕上显示时会自动隐藏系统状态栏,以便其控件可以完全访问圆形显示屏的顶部。关闭后,系统状态栏会使用窗口边衬区控制器 API 自动恢复。
切换到沉浸模式
如需切换到沉浸模式(系统状态栏和本地 TimeText 都会隐藏),请将 Modifier.suppressStatusBar 修饰符应用于应用、屏幕或组件。请为用户短暂看到的屏幕(确认叠加层、对话框)或使用整个显示屏的屏幕(全屏进度指示器)保留沉浸模式。
考虑何时使用屏幕级沉浸模式
如果只有应用中的特定屏幕应为全屏或沉浸式,请将 Modifier.suppressStatusBar 应用于 ScreenScaffold。当该屏幕处于活动状态时,ScreenScaffold 会自动隐藏系统状态栏,并将顶部状态栏边衬内边距收起至 0.dp。当您返回到其他界面时,ScreenScaffold 会恢复系统状态栏:
AppScaffold { ScreenScaffold(modifier = Modifier.suppressStatusBar()) { contentPadding -> Box(modifier = Modifier.fillMaxSize().padding(contentPadding)) { // Full-screen immersive content } } }
如需在单个组件显示在屏幕上时隐藏系统状态栏,请直接将 Modifier.suppressStatusBar 应用于该组件。此修饰符有助于应用于全屏组件,例如全屏进度指示器和自定义对话框窗口。
考虑何时使用应用级沉浸模式
如果您的整个应用都是沉浸式全屏体验,请将 Modifier.suppressStatusBar 应用于 AppScaffold,以在所有屏幕上隐藏系统状态栏:
// Apply Modifier.suppressStatusBar() to AppScaffold to suppress the status bar // and collapse insets across all child screens. AppScaffold(modifier = Modifier.suppressStatusBar()) { SwipeDismissableNavHost( navController = navController, startDestination = "home", ) { // Nested screens inherit suppression and 0.dp padding } }
显示自定义时间文本替换
如果您需要在 Wear OS 8 迁移期间在特定屏幕或整个应用中显示自定义弧形标题或暂时停用系统状态栏,则传递自定义 timeText 可组合项会抑制系统状态栏:
// Screen-level custom TimeText override: ScreenScaffold( timeText = { TimeText { timeTextCurvedText("Custom Status") } }, ) { // Content } // App-level opt-out using in-app TimeText: AppScaffold( timeText = { TimeText() }, ) { // Screens }
使用视图实现(不推荐)
如果您的应用使用 Android View 而非 Jetpack Compose for Wear OS,请使用 AndroidManifest.xml 选择启用。与最新 Alpha 版 Wear Compose Material 3(会自动启用系统状态栏)不同,基于 View 的应用必须通过在 <application> 中添加 ENABLE_GLOBAL_STATUS_BAR <meta-data> 标记来明确选择启用:
<meta-data android:name="com.google.wear.ENABLE_GLOBAL_STATUS_BAR" android:value="true" />
监控顶部窗口边衬区
使用 ViewCompat.setOnApplyWindowInsetsListener 并检查 windowInsets.getInsets(WindowInsetsCompat.Type.statusBars()) 的值。如果为 statusBarInsets.top > 0,请移除旧版 12 点钟界面并调整顶部内边距;否则,回退到旧版界面:
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, windowInsets -> val statusBarInsets = windowInsets.getInsets( WindowInsetsCompat.Type.statusBars() ) if (statusBarInsets.top > 0) { // status bar is visible: remove legacy 12 o'clock UI and apply top inset padding view.updatePadding(top = statusBarInsets.top) } else { // status bar is not visible: fall back to legacy UI and padding } WindowInsetsCompat.CONSUMED }
以编程方式隐藏和显示状态栏
与 Compose 中的 ScreenScaffold 不同,基于 View 的应用必须使用 WindowInsetsControllerCompat 显式隐藏或显示系统状态栏(例如,在进入全屏沉浸式视图或协调滚动隐藏行为时):
val insetsController = WindowCompat.getInsetsController(window, window.decorView) // Hide the status bar insetsController.hide(WindowInsetsCompat.Type.statusBars()) // Show the status bar insetsController.show(WindowInsetsCompat.Type.statusBars())
测试应用
在 Wear OS 7.1 Beta 版预览模拟器 (API 37.2-beta1) 上测试应用时,请检查以下事项:
- 时钟仅显示一次:验证是否只有系统状态栏时间显示在 12 点钟位置,并且没有旧版应用内
TimeText和应用内容与其重叠。 - 顶部内边距:验证屏幕标题、标题和顶部按钮是否显示在状态栏下方。
- 全屏叠加层和对话框:验证对话框、选择器、步进器和自定义全屏 activity 在打开时是否会隐藏状态栏,以及在关闭时是否会恢复状态栏。