Quando lavoriamo con eventi tocco e animazioni, dobbiamo tenere in considerazione diversi aspetti rispetto a quando lavoriamo solo con le animazioni. Innanzitutto, potrebbe essere necessario interrompere un'animazione in corso quando iniziano gli eventi tocco, poiché l'interazione utente deve avere la massima priorità.
Nell'esempio riportato di seguito, utilizziamo un Animatable
per rappresentare la posizione di offset di
un componente cerchio. Gli eventi di tocco vengono elaborati con il modificatore
pointerInput
. Quando rileviamo un nuovo evento di tocco, chiamiamo animateTo
per animare il
valore di offset nella posizione del tocco. Un evento tocco può verificarsi anche durante l'animazione
e, in questo caso, animateTo
interrompe l'animazione in corso e avvia
l'animazione verso la nuova posizione di destinazione mantenendo la velocità dell'animazione
interrotta.
@Composable fun Gesture() { val offset = remember { Animatable(Offset(0f, 0f), Offset.VectorConverter) } Box( modifier = Modifier .fillMaxSize() .pointerInput(Unit) { coroutineScope { while (true) { // Detect a tap event and obtain its position. awaitPointerEventScope { val position = awaitFirstDown().position launch { // Animate to the tap position. offset.animateTo(position) } } } } } ) { Circle(modifier = Modifier.offset { offset.value.toIntOffset() }) } } private fun Offset.toIntOffset() = IntOffset(x.roundToInt(), y.roundToInt())
Un altro pattern frequente è la necessità di sincronizzare i valori di animazione con i valori
provenienti da eventi tocco, ad esempio il trascinamento. Nell'esempio riportato di seguito, vediamo "Scorri per
chiudere" implementato come Modifier
(anziché utilizzare il
composizione SwipeToDismiss
). Lo scostamento orizzontale dell'elemento è rappresentato come un
Animatable
. Questa API ha una caratteristica utile nell'animazione dei gesti. Il suo
valore può essere modificato dagli eventi tocco e dall'animazione. Quando riceviamo un
evento di atterraggio, interrompiamo Animatable
con il metodo stop
in modo che qualsiasi
animazione in corso venga intercettata.
Durante un evento di trascinamento, utilizziamo snapTo
per aggiornare il valore di Animatable
con il valore calcolato dagli eventi tocco. Per lo scorrimento, Compose fornisce
VelocityTracker
per registrare gli eventi di trascinamento e calcolare la velocità. La velocità può
essere inserita direttamente in animateDecay
per l'animazione di scorrimento. Quando vogliamo riportare
il valore di offset nella posizione originale, specifichiamo il valore di offset
target di 0f
con il metodo animateTo
.
fun Modifier.swipeToDismiss( onDismissed: () -> Unit ): Modifier = composed { val offsetX = remember { Animatable(0f) } pointerInput(Unit) { // Used to calculate fling decay. val decay = splineBasedDecay<Float>(this) // Use suspend functions for touch events and the Animatable. coroutineScope { while (true) { val velocityTracker = VelocityTracker() // Stop any ongoing animation. offsetX.stop() awaitPointerEventScope { // Detect a touch down event. val pointerId = awaitFirstDown().id horizontalDrag(pointerId) { change -> // Update the animation value with touch events. launch { offsetX.snapTo( offsetX.value + change.positionChange().x ) } velocityTracker.addPosition( change.uptimeMillis, change.position ) } } // No longer receiving touch events. Prepare the animation. val velocity = velocityTracker.calculateVelocity().x val targetOffsetX = decay.calculateTargetValue( offsetX.value, velocity ) // The animation stops when it reaches the bounds. offsetX.updateBounds( lowerBound = -size.width.toFloat(), upperBound = size.width.toFloat() ) launch { if (targetOffsetX.absoluteValue <= size.width) { // Not enough velocity; Slide back. offsetX.animateTo( targetValue = 0f, initialVelocity = velocity ) } else { // The element was swiped away. offsetX.animateDecay(velocity, decay) onDismissed() } } } } } .offset { IntOffset(offsetX.value.roundToInt(), 0) } }
Consigliati per te
- Nota: il testo del link viene visualizzato quando JavaScript è disattivato
- Animazioni basate sul valore
- Trascinare, scorrere e scorrere rapidamente
- Informazioni sui gesti