借助 Android Studio Compose 预览功能,您可以在 IDE 中直接检查和验证 Wear OS 可组合项在不同手表显示屏尺寸、圆形边框和字体缩放比例下的效果,而无需将应用部署到实体手表或模拟器。
由于 Wear OS 设备采用圆形显示屏,边角会剪裁内容,并且 TimeText 和 ScrollIndicator 等系统叠加层会沿屏幕边缘弯曲,因此专门为 Wear OS 配置预览对于尽早发现布局问题至关重要。
设置预览版依赖项
如需使用 Wear OS Compose 预览注释和设备定义,请将以下依赖项添加到模块的 build.gradle.kts 文件中:
dependencies {
// Provides @WearPreview* multipreview annotations
// (such as @WearPreviewDevices and @WearPreviewFontScales)
implementation("androidx.wear.compose:compose-ui-tooling:1.7.0")
// Provides WearDevices constants
// (such as WearDevices.SMALL_ROUND and WearDevices.LARGE_ROUND)
implementation("androidx.wear:wear-tooling-preview:1.0.0")
// Standard Compose preview support and interactive/animation inspection
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
}
选择要预览的内容:界面还是组件
预览的配置方式取决于您是预览全屏还是隔离的界面组件。
预览全屏 (AppScaffold + ScreenScaffold)
预览整个屏幕时,请务必使用 Wear 设备预览注释将屏幕可组合项同时封装在 AppScaffold 和 ScreenScaffold 中。这会渲染圆形手表显示屏,并确保:
TimeText渲染在表盘的顶部曲面边缘。ScrollIndicator会显示在右侧边框上。EdgeButton已正确定位,并在底部曲线处被剪裁。- 内容边衬区和圆形屏幕剪裁可准确反映真实的观看硬件。
@WearPreviewDevices @Composable fun WorkoutScreenPreview() { MaterialTheme { // AppScaffold provides the top-level TimeText overlay AppScaffold { // WorkoutScreen contains its own ScreenScaffold and content WorkoutScreen( heartRate = 142, elapsedTime = "12:45" ) } } }
小圆 (192x192dp)
大圆 (227x227dp)
预览隔离的组件
预览单个组件(例如自定义 Card、Button 或状态条状标签)时,请省略 device 参数,并使用具有深色背景的标准 @Preview。这可确保 Wear Material 3 颜色和对比度准确显示,而无需渲染完整的圆形手表显示屏:
@Preview( showBackground = true, backgroundColor = 0xFF000000 ) @Composable fun HeartRateCardPreview() { MaterialTheme { HeartRateCard(bpm = 142, zone = "Aerobic") } }
隔离的组件预览(无设备框架)。
内置 Multipreview 注解
androidx.wear.compose.ui.tooling.preview 软件包提供内置注释,可自动配置深色背景 (backgroundColor = 0xFF000000、showBackground = true) 和圆形手表设备尺寸:
| 注释 | 渲染的内容 | 何时使用 |
|---|---|---|
@WearPreviewSmallRound |
WearDevices.SMALL_ROUND上的 1 张预览图片(192x192dp)。 |
快速迭代最受限的圆形显示大小。 |
@WearPreviewLargeRound |
WearDevices.LARGE_ROUND(227x227dp)上显示 1 个预览。 |
检查大尺寸手表的布局密度和额外间距。 |
@WearPreviewDevices |
2 个预览版:SMALL_ROUND 和 LARGE_ROUND。 |
针对每个屏幕可组合函数的标准多设备检查。 |
@WearPreviewFontScales |
SMALL_ROUND 上的 6 个预览,涵盖所有 Wear 字体缩放比例:小 (0.94f)、正常 (1.0f)、中 (1.06f)、大 (1.12f)、较大 (1.18f) 和最大 (1.24f)。 |
检查文本换行、省略号和按钮高度扩展。 |
您可以将 @WearPreviewDevices 和 @WearPreviewFontScales 堆叠在同一预览函数上,以生成全面的测试矩阵:
@WearPreviewDevices @WearPreviewFontScales @Composable fun MessageDetailScreenPreview() { MaterialTheme { AppScaffold { MessageDetailScreen( sender = "Alex", body = "Running 5 mins late!" ) } } }
自定义预览注释和硬件规格
如果您需要更精细的控制(例如测试特定的硬件尺寸、较长的本地化字符串或最糟糕的组合),可以直接配置 @Preview,也可以定义自己的自定义多预览注释。
可用的 WearDevices 常量和自定义硬件规格
androidx.wear.tooling.preview.devices.WearDevices 对象提供标准设备 ID:
WearDevices.SMALL_ROUND("id:wearos_small_round",192x192dp)WearDevices.LARGE_ROUND("id:wearos_large_round",227x227dp)
如需在超大圆形显示屏(例如 44 毫米至 45 毫米的手表或 240x240dp 的 Ultra 型号)上进行预览,请将自定义 spec: 字符串传递给 device 形参:
@Preview( name = "XL Round Watch (240dp)", device = "spec:width=240dp,height=240dp,dpi=320,isRound=true", showBackground = true, backgroundColor = 0xFF000000 ) @Composable fun WorkoutScreenXlPreview() { MaterialTheme { AppScaffold { WorkoutScreen(heartRate = 142, elapsedTime = "12:45") } } }
创建自定义多预览注释
如需检查极端情况,请创建自定义多预览注释,将最小的圆形屏幕与最大的字体缩放比例和详细的语言区域(例如德语)配对,同时搭配标准的圆形大屏幕:
@Preview( name = "1. Standard Large Round", group = "Layout extremes", device = WearDevices.LARGE_ROUND, backgroundColor = 0xFF000000, showBackground = true ) @Preview( name = "2. Extreme Small Round (Largest Font + German)", group = "Layout extremes", device = WearDevices.SMALL_ROUND, fontScale = 1.24f, locale = "de-rDE", backgroundColor = 0xFF000000, showBackground = true ) annotation class WearPreviewExtremes
1. 标准大圆
2. 极小圆形(最大字号 + 德语)
预览滚动列 (TransformingLazyColumn)
默认情况下,TransformingLazyColumn 会初始化为第一个项 (index = 0) 位于屏幕顶部。不过,在 Wear OS 上,当列表项靠近屏幕顶部和底部的曲面边缘时,它们的高度和圆角 (SurfaceTransformation) 会发生变化,并且只有在滚动到底部时才会显示 EdgeButton。
如需预览列表在部分向下滚动或滚动到底部时的外观,请执行以下操作:
第 1 步:在屏幕可组合项中提升 TransformingLazyColumnState
允许屏幕可组合项接受以 rememberTransformingLazyColumnState() 为默认值的 TransformingLazyColumnState 形参:
@Composable fun InboxScreen( messages: List<Message>, columnState: TransformingLazyColumnState = rememberTransformingLazyColumnState(), ) { val transformationSpec = rememberTransformationSpec() ScreenScaffold( scrollState = columnState, edgeButton = { EdgeButton(onClick = { /* Compose new */ }) { Text("New message") } } ) { contentPadding -> TransformingLazyColumn( state = columnState, contentPadding = contentPadding, ) { items(messages.size) { index -> Card( onClick = {}, modifier = Modifier .fillMaxWidth() .transformedHeight(this, transformationSpec) .minimumVerticalContentPadding( CardDefaults.minimumVerticalListContentPadding ), transformation = SurfaceTransformation(transformationSpec), ) { Text(messages[index].subject) } } } } }
第 2 步:在 @Preview 中传递 initialAnchorItemIndex
rememberTransformingLazyColumnState 接受两个可选的初始滚动参数:
initialAnchorItemIndex: Int:如果设置为非负指数(例如3),列表会初始化为以该项为中心显示在手表视口中。initialAnchorItemScrollOffset: Int:相对于居中锚定项应用的可选像素偏移量。
您可以创建并排预览,以显示同一屏幕的顶部、中间(滚动)和底部(EdgeButton 可见)状态:
@WearPreviewLargeRound @Composable fun InboxScreenTopPreview() { MaterialTheme { AppScaffold { // Default (-1): Pinned to top of list (index 0) InboxScreen(messages = sampleMessages) } } } @WearPreviewLargeRound @Composable fun InboxScreenScrolledMiddlePreview() { MaterialTheme { AppScaffold { // Centers item index 3 in the viewport, showing top/bottom item morphing InboxScreen( messages = sampleMessages, columnState = rememberTransformingLazyColumnState( initialAnchorItemIndex = 3 ) ) } } } @WearPreviewLargeRound @Composable fun InboxScreenBottomEdgeButtonPreview() { MaterialTheme { AppScaffold { // Anchors on the last item so the EdgeButton is visible at the bottom InboxScreen( messages = sampleMessages, columnState = rememberTransformingLazyColumnState( initialAnchorItemIndex = sampleMessages.lastIndex ) ) } } }
顶部(默认值 -1)
中 (initialAnchorItemIndex = 3)
底部(EdgeButton 展开)
提示:您还可以点击 Android Studio 中任意
@Preview上的开始互动模式,通过鼠标或触控板滚动TransformingLazyColumn直播,并实时检查SurfaceTransformation变形、EdgeButton入场动画和ScrollIndicator移动。
在滚动捕获 (LocalScrollCaptureInProgress) 期间保护 ScrollIndicator
当系统滚动捕获(长屏幕截图)或多帧屏幕截图测试工具捕获滚动 TransformingLazyColumn 时,Compose 会在垂直捕获和拼接多个视口图块时将 LocalScrollCaptureInProgress.current 设置为 true。
由于 ScreenScaffold 在滚动捕获期间不会自动隐藏其 scrollIndicator,因此除非您使用 !LocalScrollCaptureInProgress.current 明确保护浮动滚动条叠加层,否则该叠加层会在长屏幕截图的每个拼接图块上重复显示:
ScreenScaffold( scrollState = columnState, scrollIndicator = { if (!LocalScrollCaptureInProgress.current) { ScrollIndicator(state = columnState) } } ) { contentPadding -> // TransformingLazyColumn content... // ... }