Quando lavori con animazioni ed eventi touch, devi tenere conto di diversi aspetti rispetto a quando lavori solo con le animazioni. Prima di tutto, potremmo dover interrompere un'animazione in corso quando iniziano gli eventi touch, dato che l'interazione dell'utente dovrebbe avere la massima priorità.
Nell'esempio riportato di seguito, utilizziamo un Animatable
per rappresentare la posizione di offset di un componente cerchio. Gli eventi tocco vengono elaborati con il modificatore
pointerInput
. Quando viene rilevato un nuovo evento di tocco, chiamiamo animateTo
per animare il
valore di offset nella posizione del tocco. Può verificarsi anche un evento di tocco durante l'animazione
e, in questo caso, animateTo
interrompe l'animazione in corso e avvia
l'animazione nella nuova posizione target, 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 è che dobbiamo sincronizzare i valori dell'animazione con quelli provenienti dagli eventi touch, come il trascinamento. Nell'esempio riportato di seguito, vediamo l'implementazione di "scorri per chiudere" come Modifier
(anziché utilizzare il composable SwipeToDismiss
). Lo scostamento orizzontale dell'elemento è rappresentato come
Animatable
. Questa API ha una caratteristica utile nell'animazione dei gesti. Il suo valore può essere modificato dagli eventi touch e dall'animazione. Quando riceviamo un evento di tocco, interrompiamo Animatable
tramite il metodo stop
in modo che qualsiasi animazione in corso venga intercettata.
Durante un evento di trascinamento, utilizziamo snapTo
per aggiornare il valore Animatable
con il valore calcolato dagli eventi touch. Per il movimento brusco, Compose fornisce
VelocityTracker
per registrare gli eventi di trascinamento e calcolare la velocità. La velocità può
essere inviata direttamente a animateDecay
per l'animazione di scorrimento. Quando vogliamo far scorrere nuovamente il valore dell'offset nella posizione originale, specifichiamo il valore dell'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
- Trascina e scorri
- Informazioni sui gesti