Vorschau der Benutzeroberfläche in Compose für Wear OS ansehen

Mit Compose-Vorschauen in Android Studio können Sie Ihre Wear OS-Composables direkt in der IDE auf verschiedenen Displaygrößen, runden Lünetten und Schriftgrößen für Smartwatches prüfen und testen, ohne Ihre App auf einer physischen Smartwatch oder einem Emulator bereitstellen zu müssen.

Wear OS-Geräte haben runde Displays, bei denen Inhalte an den Ecken abgeschnitten werden. System-Overlays wie TimeText und ScrollIndicator sind entlang des Bildschirmrands gekrümmt. Daher ist es wichtig, Vorschauen speziell für Wear OS zu konfigurieren, um Layoutprobleme frühzeitig zu erkennen.


Vorschaubereitstellung einrichten

Wenn Sie Wear OS Compose-Vorschaubemerkungen und Gerätedefinitionen verwenden möchten, fügen Sie der build.gradle.kts-Datei Ihres Moduls die folgenden Abhängigkeiten hinzu:

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")
}

Auswählen, was in der Vorschau angezeigt werden soll: Bildschirme oder Komponenten

Wie Sie eine Vorschau konfigurieren, hängt davon ab, ob Sie eine Vollbildvorschau oder eine isolierte UI-Komponente verwenden.

Vollbildvorschau (AppScaffold + ScreenScaffold)

Wenn Sie eine Vorschau eines gesamten Bildschirms anzeigen, umschließen Sie das Bildschirm-Composable immer mit AppScaffold und ScreenScaffold und verwenden Sie eine Wear-Geräte-Vorschau-Annotation. Dadurch wird das runde Display der Smartwatch gerendert und Folgendes sichergestellt:

  • TimeText wird am oberen gebogenen Rand des Zifferblatts gerendert.
  • ScrollIndicator wird am rechten Gehäuserand angezeigt.
  • EdgeButton ist richtig positioniert und an der unteren Kurve abgeschnitten.
  • Das Content-Padding und das Zuschneiden auf runde Displays entsprechen der tatsächlichen Hardware von Smartwatches.
@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"
            )
        }
    }
}
WorkoutScreenPreview wird auf WearDevices.SMALL_ROUND gerendert

Klein rund (192 × 192 dp)

WorkoutScreenPreview wird auf WearDevices.LARGE_ROUND gerendert

Großes rundes Symbol (227 × 227 dp)

Isolierte Komponenten in der Vorschau ansehen

Wenn Sie eine Vorschau einzelner Komponenten wie eines benutzerdefinierten Card-, Button- oder Status-Chips anzeigen lassen, lassen Sie den Parameter device weg und verwenden Sie ein Standard-@Preview mit dunklem Hintergrund. So werden Farben und Kontrast von Wear Material 3 korrekt dargestellt, ohne dass ein vollständiges rundes Zifferblatt gerendert werden muss:

@Preview(
    showBackground = true,
    backgroundColor = 0xFF000000
)
@Composable
fun HeartRateCardPreview() {
    MaterialTheme {
        HeartRateCard(bpm = 142, zone = "Aerobic")
    }
}
Isolierte Komponentenvorschau der Herzfrequenzkarte ohne Smartwatch-Rahmen

Vorschau der isolierten Komponente (ohne Geräte-Frame)


Integrierte Multipreview-Anmerkungen

Das Paket androidx.wear.compose.ui.tooling.preview bietet integrierte Annotationen, mit denen automatisch dunkle Hintergründe (backgroundColor = 0xFF000000, showBackground = true) und kreisförmige Smartwatch-Abmessungen konfiguriert werden:

Annotation Was gerendert wird Anwendung
@WearPreviewSmallRound 1 Vorschau für WearDevices.SMALL_ROUND (192 × 192 dp). Schnelle Iteration bei der am stärksten eingeschränkten runden Anzeigegröße.
@WearPreviewLargeRound 1 Vorschau auf WearDevices.LARGE_ROUND (227 × 227 dp). Prüfen der Layoutdichte und des zusätzlichen Abstands auf größeren Smartwatches.
@WearPreviewDevices 2 Vorschauen: SMALL_ROUND und LARGE_ROUND. Standardmäßige Prüfung auf mehreren Geräten für jede Bildschirm-Composable-Funktion.
@WearPreviewFontScales 6 Vorschauen auf SMALL_ROUND für alle Wear-Schriftgrößen: Klein (0.94f), Normal (1.0f), Mittel (1.06f), Groß (1.12f), Größer (1.18f) und Am größten (1.24f). Prüfen, ob der Text umgebrochen und gekürzt wird und ob die Schaltflächenhöhe erweitert wird.

Sie können @WearPreviewDevices und @WearPreviewFontScales in derselben Vorschaufunktion kombinieren, um eine umfassende Testmatrix zu erstellen:

@WearPreviewDevices
@WearPreviewFontScales
@Composable
fun MessageDetailScreenPreview() {
    MaterialTheme {
        AppScaffold {
            MessageDetailScreen(
                sender = "Alex",
                body = "Running 5 mins late!"
            )
        }
    }
}

Benutzerdefinierte Vorschau-Anmerkungen und Hardwarespezifikationen

Wenn Sie eine genauere Steuerung benötigen, z. B. um bestimmte Hardwareabmessungen, lange lokalisierte Strings oder Worst-Case-Kombinationen zu testen, können Sie @Preview direkt konfigurieren oder eigene benutzerdefinierte Multipreview-Anmerkungen definieren.

Verfügbare WearDevices-Konstanten und benutzerdefinierte Hardwarespezifikationen

Das androidx.wear.tooling.preview.devices.WearDevices-Objekt enthält Standardgeräte-IDs:

  • WearDevices.SMALL_ROUND ("id:wearos_small_round", 192 × 192 dp)
  • WearDevices.LARGE_ROUND ("id:wearos_large_round", 227 × 227 dp)

Wenn Sie eine Vorschau auf extra großen runden Displays (z. B. 44–45 mm-Smartwatches oder Ultra-Modelle mit 240 × 240 dp) ansehen möchten, übergeben Sie einen benutzerdefinierten spec:-String an den Parameter 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")
        }
    }
}

Benutzerdefinierte Multi-Preview-Anmerkung erstellen

Wenn Sie ein extremes Szenario untersuchen möchten, erstellen Sie eine benutzerdefinierte Multi-Preview-Anmerkung, in der der kleinste runde Bildschirm mit der größten Schriftgröße und einem ausführlichen Gebietsschema (z. B. Deutsch) sowie einem standardmäßigen großen runden Bildschirm kombiniert werden:

@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
Vorschau für Standard-Rundschreiben

1. Standard – Groß – Rund

Extrem klein, rund, mit größter Schrift

2. Extrem klein, rund (größte Schriftart + Deutsch)


Scrollspalten in der Vorschau ansehen (TransformingLazyColumn)

Standardmäßig wird ein TransformingLazyColumn mit dem ersten Element (index = 0) initialisiert, das oben auf dem Bildschirm angepinnt ist. Bei Wear OS ändern Elemente jedoch ihre Höhe und abgerundeten Ecken (SurfaceTransformation), wenn sie sich den oberen und unteren gekrümmten Rändern des Displays nähern. Das EdgeButton wird nur angezeigt, wenn zum unteren Rand gescrollt wird.

So sehen Sie eine Vorschau Ihrer Liste, wenn sie teilweise oder ganz nach unten gescrollt wird:

Schritt 1: TransformingLazyColumnState in Ihrem Bildschirm-Composable-Element einbinden

Lassen Sie zu, dass Ihr Screen-Composable einen TransformingLazyColumnState-Parameter mit rememberTransformingLazyColumnState() als Standardwert akzeptiert:

@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)
                }
            }
        }
    }
}

Schritt 2: initialAnchorItemIndex in Ihrem @Preview bestehen

rememberTransformingLazyColumnState akzeptiert zwei optionale Parameter für den anfänglichen Bildlauf:

  • initialAnchorItemIndex: Int: Wenn dieser Wert auf einen nicht negativen Index (z. B. 3) festgelegt ist, wird die Liste mit diesem Element in der Mitte des Smartwatch-Displays initialisiert.
  • initialAnchorItemScrollOffset: Int: Optionaler Pixel-Offset, der relativ zum zentrierten Anker-Element angewendet wird.

Sie können nebeneinander angeordnete Vorschauen erstellen, die den oberen, mittleren (gescrollt) und unteren (EdgeButton sichtbar) Zustand desselben Bildschirms zeigen:

@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
                )
            )
        }
    }
}
InboxScreen oben in der Liste angepinnt

Oben (Standard -1)

InboxScreen scrolled to middle index 3

Mitte (initialAnchorItemIndex = 3)

Posteingangsbildschirm, der nach unten gescrollt wurde, mit maximiertem EdgeButton

Unten (EdgeButton erweitert)

Tipp:Sie können auch in Android Studio auf ein beliebiges @Preview klicken und dann Interaktiven Modus starten auswählen, um das TransformingLazyColumn mit der Maus oder dem Touchpad zu scrollen und SurfaceTransformation-Morphing, EdgeButton-Eingangsanimationen und ScrollIndicator-Bewegungen in Echtzeit zu beobachten.

Guard ScrollIndicator während der Aufnahme von Scroll-Screenshots (LocalScrollCaptureInProgress)

Wenn mit den Tools zum Erstellen von Screenshots mit Scrollfunktion (lange Screenshots) oder zum Testen von Screenshots mit mehreren Frames ein scrollender TransformingLazyColumn aufgenommen wird, legt Compose LocalScrollCaptureInProgress.current auf true fest, während mehrere Viewport-Kacheln vertikal aufgenommen und zusammengefügt werden.

Da ScreenScaffold seine scrollIndicator nicht automatisch ausblendet, wenn ein Screenshot mit Scrollen aufgenommen wird, wird das schwebende Bildlaufleisten-Overlay auf jeder zusammengefügten Kachel eines langen Screenshots wiederholt angezeigt, sofern Sie es nicht explizit mit !LocalScrollCaptureInProgress.current schützen:

ScreenScaffold(
    scrollState = columnState,
    scrollIndicator = {
        if (!LocalScrollCaptureInProgress.current) {
            ScrollIndicator(state = columnState)
        }
    }
) { contentPadding ->
    // TransformingLazyColumn content...
    // ...
}