Saisie par dispositif rotatif avec Compose

La saisie par dispositif rotatif fait référence aux entrées effectuées par un utilisateur sur sa montre via un mécanisme qui tourne. En moyenne, les utilisateurs ne passent que quelques secondes sur leur montre. Vous pouvez améliorer l'expérience utilisateur en utilisant la saisie par dispositif rotatif pour permettre à l'utilisateur d'effectuer rapidement diverses tâches.

Sur la plupart des montres, les trois principales sources de saisie par dispositif rotatif incluent le bouton latéral rotatif et un contour physique ou tactile qui est une zone tactile circulaire située autour de l'écran. Bien que le comportement attendu puisse varier en fonction du type d'entrée, assurez-vous de permettre la saisie par dispositif rotatif pour toutes les interactions essentielles.

Défilement

La plupart des utilisateurs s'attendent à ce que les applications prennent en charge le geste de défilement. Pendant le défilement du contenu, fournissez aux utilisateurs un indice visuel en réponse à une interaction avec un dispositif rotatif. Les indices visuels peuvent inclure des indicateurs de position pour le défilement vertical ou des indicateurs de page.

ScalingLazyColumn et Picker acceptent le geste de défilement par défaut, à condition de placer ces composants dans un Scaffold. Scaffold fournit la structure de mise en page de base des applications Wear OS et contient déjà un emplacement destiné à un indicateur de défilement. Pour afficher la progression du défilement, créez un indicateur de position en fonction de l'objet d'état de la liste, comme indiqué dans l'extrait de code suivant:

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

Vous pouvez configurer un comportement d'ancrage pour ScalingLazyColumn à l'aide de ScalingLazyColumnDefaults.snapFlingBehavior, comme indiqué dans l'extrait de code suivant:

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

    val state = rememberScalingLazyListState()
    ScalingLazyColumn(
        modifier = Modifier.fillMaxWidth(),
        state = state,
        flingBehavior = ScalingLazyColumnDefaults.snapFlingBehavior(state = state)
    ) {
        // Content goes here
        // ...
    }
}

Actions personnalisées

Vous pouvez également créer des actions personnalisées qui réagissent à la saisie par dispositif rotatif dans votre application. Par exemple, utilisez la saisie par dispositif rotatif pour faire un zoom avant ou arrière, ou pour contrôler le volume dans une application multimédia.

Si votre composant n'est pas compatible de manière native avec les événements de défilement, tels que le contrôle du volume, vous pouvez gérer vous-même les événements de défilement.

// VolumeScreen.kt

val focusRequester: FocusRequester = remember { FocusRequester() }

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

Créez un état personnalisé géré dans le modèle de vue et un rappel personnalisé permettant de traiter les événements de défilement rotatif.

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

Par souci de simplicité, l'exemple précédent utilise des valeurs de pixel qui, si elles sont réellement utilisées, sont susceptibles d'être trop sensibles.

Utilisez le rappel une fois que vous avez reçu les événements, comme illustré dans l'extrait suivant.

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

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