Функция предварительного просмотра Compose в Android Studio позволяет проверять и подтверждать работоспособность ваших компонентов Wear OS на разных размерах экрана часов, с круглыми рамками и разными масштабами шрифтов непосредственно в IDE — без развертывания приложения на физических часах или эмуляторе.
Поскольку устройства 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 )
При предварительном просмотре всего экрана всегда оборачивайте компонентный экран в AppScaffold и ScreenScaffold используя аннотацию предварительного просмотра устройства Wear. Это отобразит круглый дисплей часов и обеспечит следующее:
-
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") } }

Предварительный просмотр изолированного компонента (без рамки устройства).
Встроенные аннотации для множественного просмотра
Пакет androidx.wear.compose.ui.tooling.preview предоставляет встроенные аннотации, которые автоматически настраивают темный фон ( backgroundColor = 0xFF000000 , showBackground = true ) и круглые размеры часов:
| Аннотация | Что это отображает | Когда использовать |
|---|---|---|
@WearPreviewSmallRound | 1 предварительный просмотр на WearDevices.SMALL_ROUND (192x192dp). | Быстрая итерация для наиболее ограниченного размера круглого дисплея. |
@WearPreviewLargeRound | 1 предварительный просмотр на WearDevices.LARGE_ROUND (227x227dp). | Проверка плотности расположения элементов и избыточного расстояния между ними на часах больших размеров. |
@WearPreviewDevices | 2 варианта предварительного просмотра : SMALL_ROUND и LARGE_ROUND . | Стандартная проверка на совместимость с несколькими устройствами для каждого компонуемого экрана. |
@WearPreviewFontScales | 6 вариантов предварительного просмотра для SMALL_ROUND во всех масштабах шрифта Wear: Small ( 0.94f ), Normal ( 1.0f ), Medium ( 1.06f ), Large ( 1.12f ), Larger ( 1.18f ) и Largest ( 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 предоставляет стандартные идентификаторы устройств:
-
WearDevices.SMALL_ROUND("id:wearos_small_round", 192x192dp) -
WearDevices.LARGE_ROUND("id:wearos_large_round", 227x227dp)
Для предварительного просмотра на очень больших круглых дисплеях (например, на часах диаметром 44–45 мм или моделях Ultra с разрешением 240x240 пикселей) передайте пользовательскую строку 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 в ваш компонентный экран.
Разрешите вашему компоненту экрана принимать параметр TransformingLazyColumnState со значением rememberTransformingLazyColumnState() по умолчанию:
@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: Передайте initialAnchorItemIndex в ваш @Preview
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 )

Middle ( initialAnchorItemIndex = 3 )

Внизу ( EdgeButton развернута)
Совет: Вы также можете нажать кнопку «Запустить интерактивный режим» на любом элементе
@Previewв Android Studio, чтобы прокручиватьTransformingLazyColumnв реальном времени с помощью мыши или трекпада и наблюдать за морфингомSurfaceTransformation, анимацией появленияEdgeButtonи движениемScrollIndicatorв реальном времени.
Защита ScrollIndicator во время захвата прокрутки ( LocalScrollCaptureInProgress )
Когда системная функция захвата прокрутки (для длинных скриншотов) или инструменты тестирования многокадровых скриншотов захватывают прокручиваемый TransformingLazyColumn , Compose устанавливает LocalScrollCaptureInProgress.current в значение true во время захвата и вертикального соединения нескольких фрагментов области просмотра.
Поскольку ScreenScaffold не скрывает автоматически свой scrollIndicator во время захвата прокрутки, плавающая полоса прокрутки будет повторяться на каждом фрагменте длинного скриншота, если вы явно не защитите её с помощью !LocalScrollCaptureInProgress.current :
ScreenScaffold( scrollState = columnState, scrollIndicator = { if (!LocalScrollCaptureInProgress.current) { ScrollIndicator(state = columnState) } } ) { contentPadding -> // TransformingLazyColumn content... // ... }