Input rotatorio con Compose

Per input rotatorio si intende l'input di parti dello smartwatch che ruotano o ruotano. In media, gli utenti trascorrono solo pochi secondi interagendo con lo smartwatch. Puoi migliorare l'esperienza utente utilizzando l'input rotatorio per consentire all'utente di svolgere rapidamente varie attività.

Le tre sorgenti principali di input rotatorio sulla maggior parte degli smartwatch includono il pulsante laterale rotante (RSB) e una ghiera fisica o una ghiera touch, che è una zona touch circolare intorno allo schermo. Sebbene il comportamento previsto possa variare in base al tipo di input, assicurati di supportare l'input rotatorio per tutte le interazioni essenziali.

Scorri

La maggior parte degli utenti si aspetta che le app supportino il gesto di scorrimento. Mentre i contenuti scorrono sullo schermo, fornisci agli utenti un feedback visivo in risposta alle interazioni rotatorie. Il feedback visivo può includere indicatori di posizione per lo scorrimento verticale o indicatori di pagina.

Implementare lo scorrimento rotatorio utilizzando Compose per Wear OS. Questo esempio descrive un'app con un'impalcatura e un ScalingLazyColumn che scorre verticalmente. Lo scaffold fornisce la struttura del layout di base per le app per Wear OS e ha già uno slot per un indicatore di scorrimento. Per visualizzare l'avanzamento dello scorrimento, crea un indicatore di posizione basato sull'oggetto dello stato elenco. Le viste scorrevoli, tra cui ScalingLazyColumn, hanno già uno stato scorrevole per l'aggiunta di input rotatorio. Per ricevere eventi di scorrimento rotatorio, procedi nel seguente modo:

  1. Richiedi esplicitamente lo stato attivo utilizzando FocusRequester.
  2. Aggiungi il modificatore onRotaryScrollEvent per intercettare gli eventi generati dal sistema quando un utente ruota la corona o la ruota. Ogni evento rotatorio ha un valore in pixel impostato e scorre verticalmente o orizzontalmente. Il modificatore dispone inoltre di un callback per indicare se l'evento viene consumato e interrompe la propagazione dell'evento agli elementi padre quando viene consumato.
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(),
        state = listState
    ) { ... }
}

Valori discreti

Utilizza le interazioni rotative per regolare anche i valori discreti, ad esempio per regolare la luminosità nelle impostazioni o selezionare i numeri nel selettore temporale quando imposti una sveglia.

Come per ScalingLazyColumn, il selettore, il cursore, lo stepper e gli altri componenti componibili devono avere uno stato attivo per ricevere input rotatorio. In caso di più target scorrevoli sullo schermo, come ore e minuti nel selettore dell'ora, crea un FocusRequester per ogni target e gestisci la variazione dello stato attivo di conseguenza quando l'utente tocca ore o minuti.

@Composable
fun TimePicker() {
    var selectedColumn by remember { mutableStateOf(0) }
    val focusRequester1 = remember { FocusRequester() }
    val focusRequester2 = remember { FocusRequester() }

    Row {
       Picker(...)
       Picker(...)
    }

    LaunchedEffect(selectedColumn) {
        listOf(focusRequester1,
               focusRequester2)[selectedColumn]
            .requestFocus()
    }
}

Azioni personalizzate

Puoi anche creare azioni personalizzate che rispondono all'input rotatorio nella tua app. Ad esempio, utilizza l'input rotatorio per aumentare e diminuire lo zoom o per regolare il volume in un'app multimediale.

Se il componente non supporta in modo nativo gli eventi di scorrimento come il controllo del volume, puoi gestire gli eventi di scorrimento autonomamente.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

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

Crea un modello in visualizzazione gestito dello stato personalizzato e un callback personalizzato utilizzato per elaborare gli eventi di scorrimento rotatorio.

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

Per semplicità, l'esempio precedente utilizza valori di pixel che, se utilizzati effettivamente, potrebbero essere eccessivamente sensibili.

Utilizza il callback dopo aver ricevuto gli eventi, come mostrato nello snippet seguente.

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

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

Risorse aggiuntive

Prendi in considerazione l'utilizzo di Horologist, un progetto open source di Google che fornisce un insieme di librerie Wear che integrano le funzionalità fornite da Compose per Wear OS e da altre API Wear OS. L'orologo fornisce l'implementazione per casi d'uso avanzati e molti dettagli specifici.

Ad esempio, la sensibilità di diverse origini di input rotatorio può variare. Per una transizione più fluida tra i valori, puoi valutare la limitazione o aggiungere agganciamenti o animazioni per la transizione. In questo modo, la velocità di rotazione risulta più naturale per gli utenti. L'orologo include modificatori per componenti scorrevoli e per valori discreti. Include inoltre utilità per gestire lo stato attivo e una libreria UI audio per implementare il controllo del volume con la tecnologia aptica.

Per maggiori informazioni, vedi la pagina dell'orologo su GitHub.