Podglądy w Android Studio Compose umożliwiają sprawdzanie i weryfikowanie komponentów Wear OS na różnych rozmiarach wyświetlaczy zegarków, okrągłych ramkach i skalach czcionek bezpośrednio w IDE – bez wdrażania aplikacji na fizycznym zegarku lub emulatorze.
Urządzenia z Wear OS mają okrągłe wyświetlacze, na których rogi przycinają treści, a nakładki systemowe, takie jak TimeText i ScrollIndicator, są zakrzywione wzdłuż krawędzi ekranu. Dlatego skonfigurowanie podglądów specjalnie dla Wear OS jest niezbędne, aby wcześnie wykrywać problemy z układem.
Konfigurowanie zależności podglądu
Aby używać adnotacji podglądu Wear OS Compose i definicji urządzeń, dodaj te zależności do pliku build.gradle.kts modułu:
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")
}
Wybieranie elementów do wyświetlenia w podglądzie: ekrany czy komponenty
Sposób konfiguracji podglądu zależy od tego, czy wyświetlasz podgląd pełnego ekranu czy wyodrębnionego komponentu interfejsu.
Podgląd pełnoekranowy (AppScaffold + ScreenScaffold)
Podczas wyświetlania podglądu całego ekranu zawsze umieszczaj komponent ekranu w AppScaffold i ScreenScaffold, używając adnotacji podglądu urządzenia Wear. Spowoduje to wyświetlenie okrągłego ekranu zegarka i zapewni, że:
TimeTextjest renderowany na górnej zakrzywionej krawędzi tarczy zegara.ScrollIndicatorpojawi się wzdłuż prawej ramki.EdgeButtonjest prawidłowo umieszczony i przypięty w dolnej części.- Wypełnienie treści i przycinanie okrągłego ekranu dokładnie odzwierciedlają rzeczywiste działanie sprzętu zegarka.
@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" ) } } }
Mały okrągły (192 x 192 dp)
Duży okrągły (227x227dp)
Wyświetlanie podglądu wyodrębnionych komponentów
Podczas wyświetlania podglądu poszczególnych komponentów, takich jak niestandardowy element Card, Button lub chip stanu, pomiń parametr device i użyj standardowego elementu @Preview z ciemnym tłem. Dzięki temu kolory i kontrast Wear Material 3 będą wyświetlane prawidłowo bez renderowania pełnego okrągłego wyświetlacza zegarka:
@Preview( showBackground = true, backgroundColor = 0xFF000000 ) @Composable fun HeartRateCardPreview() { MaterialTheme { HeartRateCard(bpm = 142, zone = "Aerobic") } }
Podgląd wyodrębnionego komponentu (bez ramki urządzenia).
Wbudowane adnotacje w wielokrotnym podglądzie
Pakiet androidx.wear.compose.ui.tooling.preview zawiera wbudowane adnotacje, które automatycznie konfigurują ciemne tła (backgroundColor = 0xFF000000, showBackground = true) i okrągłe wymiary urządzenia:
| Adnotacja | Co renderuje | Kiedy używać |
|---|---|---|
@WearPreviewSmallRound |
1 podgląd na urządzeniu WearDevices.SMALL_ROUND (192x192 dp). |
Szybkie iteracje w przypadku najbardziej ograniczonego rozmiaru okrągłego wyświetlacza. |
@WearPreviewLargeRound |
1 podgląd na urządzeniu WearDevices.LARGE_ROUND (227x227 dp). |
Sprawdzanie gęstości układu i dodatkowych odstępów na większych zegarkach. |
@WearPreviewDevices |
2 podglądy: SMALL_ROUND i LARGE_ROUND. |
Standardowe sprawdzanie na wielu urządzeniach w przypadku każdego komponentu ekranu. |
@WearPreviewFontScales |
6 podglądów na SMALL_ROUND we wszystkich skalach czcionek Wear: mała (0.94f), normalna (1.0f), średnia (1.06f), duża (1.12f), większa (1.18f) i największa (1.24f). |
Sprawdzanie zawijania tekstu, stosowania wielokropka i zwiększania wysokości przycisku. |
Możesz połączyć @WearPreviewDevices i @WearPreviewFontScales w tej samej funkcji podglądu, aby wygenerować kompleksowy zestaw testów:
@WearPreviewDevices @WearPreviewFontScales @Composable fun MessageDetailScreenPreview() { MaterialTheme { AppScaffold { MessageDetailScreen( sender = "Alex", body = "Running 5 mins late!" ) } } }
Niestandardowe adnotacje w podglądzie i specyfikacje sprzętu
Jeśli potrzebujesz większej kontroli, np. chcesz przetestować konkretne wymiary sprzętu, długie zlokalizowane ciągi znaków lub kombinacje w najgorszym przypadku, możesz skonfigurować @Preview bezpośrednio lub zdefiniować własne niestandardowe adnotacje do podglądu wielu wersji.
Dostępne stałe WearDevices i niestandardowe specyfikacje sprzętowe
Obiekt androidx.wear.tooling.preview.devices.WearDevices zawiera standardowe identyfikatory urządzeń:
WearDevices.SMALL_ROUND("id:wearos_small_round", 192x192dp)WearDevices.LARGE_ROUND("id:wearos_large_round", 227x227dp)
Aby wyświetlić podgląd na bardzo dużych okrągłych wyświetlaczach (np. zegarkach o średnicy 44–45 mm lub modelach Ultra o rozdzielczości 240 x 240 dp), przekaż niestandardowy ciąg znaków spec: do parametru 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") } } }
Tworzenie niestandardowej adnotacji z wieloma podglądami
Aby sprawdzić ekstremalny scenariusz, utwórz niestandardową adnotację z wieloma podglądami, która łączy najmniejszy okrągły ekran z największą skalą czcionki i językiem z długimi słowami (np. niemieckim) oraz standardowym dużym okrągłym ekranem:
@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. Standardowy duży okrąg
2. Ekstremalnie mała okrągła (największa czcionka + niemiecki)
Wyświetlanie podglądu przewijanych kolumn (TransformingLazyColumn)
Domyślnie element TransformingLazyColumn jest inicjowany z pierwszym elementem (index = 0) przypiętym u góry ekranu. Na Wear OS elementy zmieniają jednak wysokość i zaokrąglone rogi (SurfaceTransformation), gdy zbliżają się do zakrzywionych krawędzi ekranu u góry i u dołu, a EdgeButton pojawia się tylko po przewinięciu do dołu.
Aby zobaczyć podgląd listy po przewinięciu jej do połowy lub do końca:
Krok 1. Przenieś TransformingLazyColumnState do komponentu kompozycyjnego ekranu
Zezwól na akceptowanie przez komponent ekranu parametru TransformingLazyColumnState z wartością domyślną 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) } } } } }
Krok 2. Przekaż initialAnchorItemIndex w @Preview
rememberTransformingLazyColumnState akceptuje 2 opcjonalne parametry początkowego przewijania:
initialAnchorItemIndex: Int: jeśli ustawisz indeks nieujemny (np.3), lista zostanie zainicjowana z tym elementem wyśrodkowanym w obszarze wyświetlania zegarka.initialAnchorItemScrollOffset: Int: opcjonalne przesunięcie piksela zastosowane względem wyśrodkowanego elementu kotwicy.
Możesz utworzyć podglądy obok siebie, które pokazują stany górny, środkowy (po przewinięciu) i dolny (EdgeButton widoczny) tego samego ekranu:
@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 ) ) } } }
Góra (domyślnie -1)
Środkowy (initialAnchorItemIndex = 3)
Dół (EdgeButton rozwinięty)
Wskazówka: możesz też kliknąć Start Interactive Mode (Włącz tryb interaktywny) w dowolnym
@Previeww Android Studio, aby przewijaćTransformingLazyColumnna żywo za pomocą myszy lub trackpada i sprawdzaćSurfaceTransformationprzekształcenia,EdgeButtonanimacje wejścia iScrollIndicatorruch w czasie rzeczywistym.
Ochrona ScrollIndicator podczas robienia zrzutu ekranu z przewijaniem (LocalScrollCaptureInProgress)
Gdy systemowe narzędzia do przechwytywania zrzutów ekranu z przewijaniem (długich zrzutów ekranu) lub zrzutów wieloklatkowych przechwytują przewijany element TransformingLazyColumn, Compose ustawia wartość LocalScrollCaptureInProgress.current na true podczas przechwytywania i łączenia wielu kafelków widoku w pionie.
Ponieważ ScreenScaffold nie ukrywa automatycznie swojego elementu scrollIndicator
podczas przechwytywania przewijania, nakładka pływającego paska przewijania będzie powtarzana na
każdym połączonym kafelku długiego zrzutu ekranu, chyba że jawnie zabezpieczysz ją za pomocą
!LocalScrollCaptureInProgress.current:
ScreenScaffold( scrollState = columnState, scrollIndicator = { if (!LocalScrollCaptureInProgress.current) { ScrollIndicator(state = columnState) } } ) { contentPadding -> // TransformingLazyColumn content... // ... }