Rotierende Eingabe mit „Compose“

Die Dreheingabe bezieht sich auf Eingaben von Teilen Ihrer Uhr, die sich drehen oder drehen. An verwenden Nutzer im Durchschnitt nur wenige Sekunden mit ihrer Uhr. Ich können Sie die Nutzererfahrung verbessern, indem Sie um verschiedene Aufgaben schnell zu erledigen.

Die drei Hauptquellen für den Drehknopf bei den meisten Uhren ist die rotierende Seite (RSB) und entweder einen physischen oder einen runden Touchbereich um den Bildschirm herum. Das erwartete Verhalten kann je nach Drehknopf bei allen wichtigen Interaktionen unterstützen.

Scrollen

Die meisten Nutzer erwarten, dass Apps die Scroll-Geste unterstützen. Beim Scrollen der Inhalte auf dem Bildschirm und geben den Nutzenden als Reaktion auf Drehinteraktionen visuelles Feedback. Visuelles Feedback kann Positionsanzeigen für vertikales Scrollen oder Seitenindikatoren.

Implementieren Sie das Tool zum Scrollen mit der Funktion „Compose“ für Wear OS. Dieses Beispiel beschreibt eine App mit einem Scaffold und einem ScalingLazyColumn, vertikal scrollt. Das Gerüst stellt die grundlegende Layout-Struktur bereit. für Wear OS-Apps und hat bereits eine Anzeigenfläche für eine Scroll-Anzeige. Bis den Scroll-Fortschritt anzeigen, einen Positionsindikator basierend auf das Listenstatusobjekt. Scrollbare Ansichten, darunter ScalingLazyColumn, haben bereits einen scrollbaren Zustand zum Hinzufügen eines Drehknopfs. Empfangen Dreh-Scroll-Ereignissen folgende Schritte aus:

  1. Fordere den Fokus explizit mit FocusRequester an. Verwenden Sie HierarchicalFocusCoordinator für komplexere Fälle, wie mehrere ScalingLazyColumns-Objekte in einem HorizontalPager.

  2. Den onRotaryScrollEvent-Modifikator hinzufügen, um Ereignisse abzufangen, die vom System erfasst werden wird generiert, wenn ein Nutzer die Krone oder den Glasrand dreht. Jedes Drehereignis einen festgelegten Pixelwert hat und vertikal oder horizontal scrollt. Der Modifizierer enthält einen Callback, der angibt, ob das Ereignis verarbeitet wurde, und stoppt die Ereignisweitergabe. an die Eltern weitergegeben werden.

val listState = rememberScalingLazyListState()
Scaffold(
    positionIndicator = {
        PositionIndicator(scalingLazyListState = listState)
    }
) {

    val focusRequester = rememberActiveFocusRequester()
    val coroutineScope = rememberCoroutineScope()

    ScalingLazyColumn(
        modifier = Modifier
            .onRotaryScrollEvent {
                coroutineScope.launch {
                    listState.scrollBy(it.verticalScrollPixels)
                    listState.animateScrollBy(0f)
                }
                true
            }
            .focusRequester(focusRequester)
            .focusable()
            .fillMaxSize(),
        state = listState
    ) {
        // Content goes here
        // ...
    }
}

Diskrete Werte

Drehinteraktionen verwenden, um auch diskrete Werte anzupassen, z. B. die Helligkeit in den Einstellungen ändern oder die Zahlen in der Zeitauswahl Alarm.

Ähnlich wie ScalingLazyColumn, Auswahl, Schieberegler, Stepper und andere zusammensetzbare Funktionen müssen fokussiert sein, um den Drehknopf zu empfangen. Bei mehreren scrollbaren wie Stunden und Minuten in der Zeitauswahl, erstellen Sie FocusRequester für jedes Ziel und bearbeiten Sie den Fokus entsprechend, wenn tippt der Nutzer entweder auf Stunden oder Minuten.

var selectedColumn by remember { mutableIntStateOf(0) }

val hoursFocusRequester = remember { FocusRequester() }
val minutesRequester = remember { FocusRequester() }
// ...
Scaffold(modifier = Modifier.fillMaxSize()) {
    Row(
        // ...
        // ...
    ) {
        // ...
        Picker(
            readOnly = selectedColumn != 0,
            modifier = Modifier.size(64.dp, 100.dp)
                .onRotaryScrollEvent {
                    coroutineScope.launch {
                        hourState.scrollBy(it.verticalScrollPixels)
                    }
                    true
                }
                .focusRequester(hoursFocusRequester)
                .focusable(),
            onSelected = { selectedColumn = 0 },
            // ...
            // ...
        )
        // ...
        Picker(
            readOnly = selectedColumn != 1,
            modifier = Modifier.size(64.dp, 100.dp)
                .onRotaryScrollEvent {
                    coroutineScope.launch {
                        minuteState.scrollBy(it.verticalScrollPixels)
                    }
                    true
                }
                .focusRequester(minutesRequester)
                .focusable(),
            onSelected = { selectedColumn = 1 },
            // ...
            // ...
        )
        LaunchedEffect(selectedColumn) {
            listOf(
                hoursFocusRequester,
                minutesRequester
            )[selectedColumn]
                .requestFocus()
        }
    }
}

Benutzerdefinierte Aktionen

Sie können auch benutzerdefinierte Aktionen erstellen, die auf Drehköpfe in Ihrer App reagieren. Für zum Beispiel mit dem Drehknopf zum Heran- und Herauszoomen oder zum Steuern der Lautstärke

Wenn Ihre Komponente keine Scroll-Ereignisse wie die Lautstärke unterstützt können Sie Scroll-Ereignisse selbst verwalten.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            // handle rotary scroll events
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Benutzerdefinierten Status, der im Ansichtsmodell verwaltet wird, und einen verwendeten benutzerdefinierten Callback erstellen um Dreh-Scroll-Ereignisse zu verarbeiten.

// VolumeViewModel.kt

object VolumeRange(
    public val max: Int = 10
    public val min: Int = 0
)

val volumeState: MutableStateFlow<Int> = ...

fun onVolumeChangeByScroll(pixels: Float) {
    volumeState.value = when {
        pixels > 0 -> min (volumeState.value + 1, VolumeRange.max)
        pixels < 0 -> max (volumeState.value - 1, VolumeRange.min)
    }
}

Zur Vereinfachung werden im vorherigen Beispiel Pixelwerte verwendet, die, falls sind wahrscheinlich übermäßig sensibel.

Verwenden Sie den Callback, sobald Sie die Ereignisse erhalten, wie im folgenden Snippet gezeigt.

val focusRequester: FocusRequester = remember { FocusRequester() }
val volumeState by volumeViewModel.volumeState.collectAsState()

Column(
    modifier = Modifier
        .fillMaxSize()
        .onRotaryScrollEvent {
            volumeViewModel
                .onVolumeChangeByScroll(it.verticalScrollPixels)
            true
        }
        .focusRequester(focusRequester)
        .focusable(),
) { ... }

Weitere Informationen

Sie können auch Horologist verwenden, ein Open-Source-Projekt von Google, das eine Reihe von Wear-Bibliotheken, die die Funktionen von Compose für Wear OS ergänzen und anderen Wear OS-APIs. Horologe bietet Implementierung für fortgeschrittene Einsatzmöglichkeiten Cases und viele gerätespezifische Details.

Beispielsweise kann die Empfindlichkeit verschiedener Drehknopfquellen variieren. Für flüssigeren Übergang zwischen Werten, Ratenbegrenzung oder Animationen für den Übergang. So fühlt sich das Drehen der Geschwindigkeit für Nutzenden. Der Horologe enthält Modifikatoren für scrollbare Komponenten und für diskrete Werte. Es umfasst auch Dienstprogramme zur Steuerung des Fokus und eine Audio-UI-Bibliothek, die Lautstärkeregelung mit Haptik.

Weitere Informationen finden Sie unter Horologe auf GitHub.