Las vistas previas de Compose de Android Studio te permiten inspeccionar y verificar tus elementos componibles de Wear OS en diferentes tamaños de pantalla de reloj, biseles redondos y factores de escala de fuentes directamente en el IDE, sin implementar tu app en un reloj o emulador físico.
Dado que los dispositivos Wear OS tienen pantallas circulares en las que las esquinas recortan el contenido y las superposiciones del sistema, como TimeText y ScrollIndicator, se curvan a lo largo del borde de la pantalla, es fundamental configurar las vistas previas específicamente para Wear OS para detectar problemas de diseño de forma anticipada.
Configura dependencias de vista previa
Para usar las anotaciones de vista previa y las definiciones de dispositivos de Wear OS Compose, agrega las siguientes dependencias al archivo build.gradle.kts de tu módulo:
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")
}
Elige qué mostrar en la vista previa: pantallas o componentes
La forma en que configuras una vista previa depende de si estás viendo una pantalla completa o un componente de IU aislado.
Vista previa de pantallas completas (AppScaffold + ScreenScaffold)
Cuando obtengas una vista previa de una pantalla completa, siempre incluye tu elemento componible de pantalla en AppScaffold y ScreenScaffold con una anotación de vista previa del dispositivo Wear. Esto renderiza la pantalla circular del reloj y garantiza lo siguiente:
TimeTextse renderiza en el borde superior curvo de la cara de reloj.ScrollIndicatoraparece a lo largo del bisel derecho.EdgeButtonestá bien colocado y enganchado en la curva inferior.- El relleno de contenido y el recorte de pantalla circular reflejan con precisión el hardware real del reloj.
@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" ) } } }
Pequeño y redondo (192 × 192 dp)
Redonda grande (227 x 227 dp)
Vista previa de componentes aislados
Cuando obtengas una vista previa de componentes individuales, como un Card, un Button o un chip de estado personalizados, omite el parámetro device y usa un @Preview estándar con un fondo oscuro. Esto garantiza que los colores y el contraste de Wear Material 3 aparezcan con precisión sin renderizar una pantalla de reloj circular completa:
@Preview( showBackground = true, backgroundColor = 0xFF000000 ) @Composable fun HeartRateCardPreview() { MaterialTheme { HeartRateCard(bpm = 142, zone = "Aerobic") } }
Vista previa aislada del componente (sin marco del dispositivo).
Anotaciones de vista previa múltiple integradas
El paquete androidx.wear.compose.ui.tooling.preview proporciona anotaciones integradas que configuran automáticamente fondos oscuros (backgroundColor = 0xFF000000, showBackground = true) y dimensiones circulares de dispositivos de reloj:
| Anotación | Qué renderiza | Cuándo debe utilizarse |
|---|---|---|
@WearPreviewSmallRound |
1 vista previa en WearDevices.SMALL_ROUND (192 x 192 dp). |
Iteración rápida en el tamaño de visualización circular más restringido. |
@WearPreviewLargeRound |
1 vista previa en WearDevices.LARGE_ROUND (227 x 227 dp). |
Se inspecciona la densidad del diseño y el espacio adicional en relojes más grandes. |
@WearPreviewDevices |
2 vistas previas: SMALL_ROUND y LARGE_ROUND. |
Es una verificación estándar para varios dispositivos de cada elemento componible de la pantalla. |
@WearPreviewFontScales |
6 vistas previas en SMALL_ROUND en todas las escalas de fuentes de Wear: Small (0.94f), Normal (1.0f), Medium (1.06f), Large (1.12f), Larger (1.18f) y Largest (1.24f). |
Comprobación del ajuste de texto, la elipsis y la expansión de la altura del botón |
Puedes apilar @WearPreviewDevices y @WearPreviewFontScales en la misma función de vista previa para generar una matriz de pruebas integral:
@WearPreviewDevices @WearPreviewFontScales @Composable fun MessageDetailScreenPreview() { MaterialTheme { AppScaffold { MessageDetailScreen( sender = "Alex", body = "Running 5 mins late!" ) } } }
Anotaciones de vista previa personalizadas y especificaciones de hardware
Cuando necesites un control más preciso, por ejemplo, para probar dimensiones de hardware específicas, cadenas localizadas largas o combinaciones de casos extremos, puedes configurar @Preview directamente o definir tus propias anotaciones de vista previa múltiple personalizadas.
Constantes WearDevices disponibles y especificaciones de hardware personalizadas
El objeto androidx.wear.tooling.preview.devices.WearDevices proporciona IDs de dispositivos estándar:
WearDevices.SMALL_ROUND("id:wearos_small_round", 192 × 192 dp)WearDevices.LARGE_ROUND("id:wearos_large_round", 227 x 227 dp)
Para obtener una vista previa en pantallas redondas extra grandes (como relojes de 44 a 45 mm o modelos Ultra de 240 x 240 dp), pasa una cadena spec: personalizada al parámetro 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") } } }
Crea una anotación de vista previa múltiple personalizada
Para inspeccionar una situación extrema, crea una anotación de vista previa múltiple personalizada que combine la pantalla redonda más pequeña con la escala de fuente más grande y una configuración regional detallada (como el alemán) junto con una pantalla redonda grande estándar:
@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. Redonda grande estándar
2. Redonda pequeña extrema (fuente más grande + alemán)
Vista previa de las columnas de desplazamiento (TransformingLazyColumn)
De forma predeterminada, un TransformingLazyColumn se inicializa con su primer elemento (index = 0) fijado en la parte superior de la pantalla. Sin embargo, en Wear OS, los elementos modifican su altura y sus esquinas redondeadas (SurfaceTransformation) a medida que se acercan a los bordes curvos superior e inferior de la pantalla, y el EdgeButton solo aparece cuando se desplaza hasta la parte inferior.
Para obtener una vista previa de cómo se ve tu lista cuando se desplaza hasta la mitad o hasta el final, haz lo siguiente:
Paso 1: Eleva TransformingLazyColumnState en tu elemento componible de pantalla
Permite que tu elemento componible de pantalla acepte un parámetro TransformingLazyColumnState con rememberTransformingLazyColumnState() como valor predeterminado:
@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) } } } } }
Paso 2: Pasa initialAnchorItemIndex en tu @Preview
rememberTransformingLazyColumnState acepta dos parámetros de desplazamiento inicial opcionales:
initialAnchorItemIndex: Int: Cuando se establece en un índice no negativo (por ejemplo,3), la lista se inicializa con ese elemento centrado en la ventana de visualización del reloj.initialAnchorItemScrollOffset: Int: Es el desplazamiento opcional del píxel que se aplica en relación con el elemento de anclaje centrado.
Puedes crear vistas previas una al lado de la otra que muestren los estados Superior, Medio (con desplazamiento) y Inferior (con EdgeButton visible) de la misma pantalla:
@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 ) ) } } }
Superior (predeterminado -1)
Medio (initialAnchorItemIndex = 3)
Parte inferior (EdgeButton expandido)
Nota: También puedes hacer clic en Start Interactive Mode en cualquier
@Previewde Android Studio para desplazarte por elTransformingLazyColumnen vivo con el mouse o el panel táctil, y, así, inspeccionar la transformación deSurfaceTransformation, las animaciones de entrada deEdgeButtony el movimiento deScrollIndicatoren tiempo real.
Protección ScrollIndicator durante la captura de desplazamiento (LocalScrollCaptureInProgress)
Cuando las herramientas del sistema de captura de desplazamiento (capturas de pantalla largas) o de prueba de capturas de pantalla de varios fotogramas capturan un TransformingLazyColumn de desplazamiento, Compose establece LocalScrollCaptureInProgress.current en true mientras captura y une varios mosaicos de viewport de forma vertical.
Dado que ScreenScaffold no oculta automáticamente su scrollIndicator durante la captura de desplazamiento, la superposición flotante de la barra de desplazamiento aparecerá repetida en cada mosaico unido de una captura de pantalla larga, a menos que la protejas de forma explícita con !LocalScrollCaptureInProgress.current:
ScreenScaffold( scrollState = columnState, scrollIndicator = { if (!LocalScrollCaptureInProgress.current) { ScrollIndicator(state = columnState) } } ) { contentPadding -> // TransformingLazyColumn content... // ... }