Plusieurs points sont à prendre en compte lorsque nous utilisons des événements tactiles et des animations, et pas seulement des animations. Tout d'abord, nous devrons peut-être interrompre une animation en cours lorsque les événements tactiles commencent, car la priorité doit être donnée à l'interaction de l'utilisateur.
Dans l'exemple ci-dessous, nous utilisons un Animatable
pour représenter la position décalée d'un composant de cercle. Les événements tactiles sont traités avec le modificateur pointerInput
. Lorsque nous détectons un nouvel événement d'appui, nous appelons animateTo
pour animer la valeur de décalage jusqu'à la position de l'appui. Un événement d'appui peut également se produire pendant l'animation. Dans ce cas, animateTo
interrompt l'animation en cours et la lance à la nouvelle position cible, tout en maintenant la vitesse de l'animation interrompue.
@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())
Il est aussi courant de devoir synchroniser les valeurs d'animation avec les valeurs issues d'événements tactiles, tels qu'un déplacement. Dans l'exemple ci-dessous, l'animation "Balayer pour fermer la vue" est implémentée en tant que Modifier
(au lieu d'utiliser le composable SwipeToDismiss
). Le décalage horizontal de l'élément est représenté par un Animatable
. Cette API présente une caractéristique utile dans les animations par gestes. Sa valeur peut être modifiée par les événements tactiles et l'animation. Lorsque nous recevons un événement tactile, nous arrêtons Animatable
par la méthode stop
afin d'interrompre toute animation en cours.
Lors d'un événement de déplacement, nous utilisons snapTo
pour mettre à jour la valeur Animatable
avec la valeur calculée à partir des événements tactiles. Pour le glissement d'un geste vif, Compose fournit VelocityTracker
afin d'enregistrer les événements de déplacement et de calculer la vitesse. La vitesse peut être transmise directement à animateDecay
pour cette animation de glissement. Lorsque nous voulons faire glisser à nouveau la valeur décalée vers sa position d'origine, nous spécifions la valeur décalée cible de 0f
avec la méthode 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) } }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Animations basées sur la valeur
- Glisser, balayer et lancer
- Comprendre les gestes