Le mouvement basé sur la physique est régi par la force. La force du ressort est l'une de ces forces qui guident l'interactivité et le mouvement. Une force de tension ("effet ressort") possède les propriétés suivantes : amortissement et rigidité. Dans une animation basée sur un ressort, la valeur et la vitesse sont calculées en fonction de la tension appliquée à chaque frame.
Si vous souhaitez que les animations de votre application ralentissent dans une seule direction, envisagez d'utiliser une animation de balayage basée sur la friction.
Cycle de vie d'une animation de rétroaction
Dans une animation basée sur un ressort, la classe SpringForce vous permet de personnaliser la rigidité du ressort, son coefficient d'amortissement et sa position finale. Dès que l'animation commence, la tension du ressort met à jour la valeur et la vitesse de l'animation à chaque frame. L'animation se poursuit jusqu'à ce que la force du ressort atteigne un équilibre.
Par exemple, si vous faites glisser une icône d'application sur l'écran, puis la relâchez en relevant votre doigt, l'icône revient à son emplacement d'origine sous l'effet d'une force invisible, mais familière.
La figure 1 illustre un effet de rétroaction similaire. Le signe plus (+) au centre du cercle indique la force appliquée par un geste tactile.
Créer une animation de rétroaction
Voici les étapes générales à suivre pour créer une animation de rétroaction pour votre application :
- Ajouter la bibliothèque Support Vous devez ajouter la bibliothèque Support à votre projet pour utiliser les classes d'animation de rétroaction.
- Créez une animation de rétroaction (spring) :
L'étape principale consiste à créer une instance de la classe
SpringAnimationet à définir les paramètres de comportement du mouvement. - (Facultatif) Enregistrer les écouteurs :
Enregistrez les écouteurs pour surveiller les modifications du cycle de vie de l'animation et les mises à jour de la valeur de l'animation.
Remarque : L'écouteur de mise à jour ne doit être enregistré que si vous avez besoin d'une mise à jour par frame sur les modifications de la valeur de l'animation. Un écouteur de mise à jour empêche l'animation de s'exécuter potentiellement sur un thread distinct.
- (Facultatif) Supprimez les écouteurs : Supprimez les écouteurs qui ne sont plus utilisés.
- (Facultatif) Définissez une valeur de départ Personnalisez la valeur de départ de l'animation.
- (Facultatif) Définissez une plage de valeurs : Définissez la plage de valeurs de l'animation pour limiter les valeurs à la plage minimale et maximale.
- (Facultatif) Définissez la vitesse de départ : Définissez la vitesse de départ de l'animation.
- (Facultatif) Définissez les propriétés du ressort Définissez le taux d'amortissement et la raideur du ressort.
- (Facultatif) Créez un ressort personnalisé Créez un ressort personnalisé si vous n'avez pas l'intention d'utiliser le ressort par défaut ou si vous souhaitez utiliser un ressort commun tout au long de l'animation.
- Démarrer l'animation Démarrez l'animation de rétroaction.
- (Facultatif) Annuler l'animation Annulez l'animation si l'utilisateur quitte brusquement l'application ou si la vue devient invisible.
Les sections suivantes décrivent en détail les étapes générales de création d'une animation de ressort.
Ajouter la bibliothèque Support
Pour utiliser la bibliothèque d'assistance basée sur la physique, vous devez l'ajouter à votre projet comme suit :
- Ouvrez le fichier
build.gradlede votre module d'application. Ajoutez la bibliothèque d'assistance à la section
dependencies.Groovy
dependencies { def dynamicanimation_version = '1.0.0' implementation "androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version" }
Kotlin
dependencies { val dynamicanimation_version = "1.0.0" implementation("androidx.dynamicanimation:dynamicanimation:$dynamicanimation_version") }
Pour afficher les versions actuelles de cette bibliothèque, consultez les informations sur Dynamicanimation sur la page des versions.
Créer une animation de rétroaction
La classe SpringAnimation vous permet de créer une animation de rétroaction pour un objet. Pour créer une animation de rétroaction, vous devez créer une instance de la classe SpringAnimation et fournir un objet, une propriété d'objet que vous souhaitez animer et une position de ressort finale facultative où vous souhaitez que l'animation s'arrête.
Remarque : Au moment de la création d'une animation de rétroaction, la position finale du ressort est facultative. Toutefois, il doit être défini avant le début de l'animation.
Kotlin
val springAnim = findViewById<View>(R.id.imageView).let { img -> // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0f) }
Java
final View img = findViewById(R.id.imageView); // Setting up a spring animation to animate the view’s translationY property with the final // spring position at 0. final SpringAnimation springAnim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y, 0);
L'animation basée sur le ressort peut animer les vues à l'écran en modifiant les propriétés réelles des objets de vue. Les vues suivantes sont disponibles dans le système :
ALPHA: représente la transparence alpha de la vue. La valeur par défaut est 1 (opaque). Une valeur de 0 représente une transparence totale (non visible).TRANSLATION_X,TRANSLATION_YetTRANSLATION_Z: ces propriétés contrôlent l'emplacement de la vue en tant que delta par rapport à sa coordonnée de gauche, sa coordonnée supérieure et son élévation, qui sont définies par son conteneur de mise en page.TRANSLATION_Xdécrit la coordonnée de gauche.TRANSLATION_Ydécrit la coordonnée supérieure.TRANSLATION_Zdécrit la profondeur de la vue par rapport à son élévation.
ROTATION,ROTATION_XetROTATION_Y: ces propriétés contrôlent la rotation en 2D (propriétérotation) et en 3D autour du point de pivot.SCROLL_XetSCROLL_Y: ces propriétés indiquent le décalage de défilement du bord gauche et du bord supérieur de la source en pixels. Elle indique également la position en termes de défilement de la page.SCALE_XetSCALE_Y: ces propriétés contrôlent la mise à l'échelle 2D d'une vue autour de son point de pivot.X,YetZ: il s'agit de propriétés utilitaires de base permettant de décrire l'emplacement final de la vue dans son conteneur.Xcorrespond à la somme de la valeur de gauche et deTRANSLATION_X.Ycorrespond à la somme de la valeur supérieure et deTRANSLATION_Y.Zcorrespond à la somme de la valeur d'altitude et deTRANSLATION_Z.
Enregistrer des écouteurs
La classe DynamicAnimation fournit deux écouteurs : OnAnimationUpdateListener et OnAnimationEndListener.
Ces écouteurs écoutent les mises à jour de l'animation, par exemple lorsqu'il y a un changement dans la valeur de l'animation et lorsque l'animation se termine.
OnAnimationUpdateListener
Lorsque vous souhaitez animer plusieurs vues pour créer une animation enchaînée, vous pouvez configurer OnAnimationUpdateListener pour recevoir un rappel chaque fois qu'une propriété de la vue actuelle change. Le rappel avertit l'autre vue de mettre à jour sa position de ressort en fonction de la modification apportée à la propriété de la vue actuelle. Pour enregistrer l'écouteur, procédez comme suit :
-
Appelez la méthode
addUpdateListener()et associez l'écouteur à l'animation.Remarque : Vous devez enregistrer le listener de mise à jour avant le début de l'animation. Toutefois, l'écouteur de mise à jour ne doit être enregistré que si vous avez besoin d'une mise à jour par frame sur les modifications de la valeur d'animation. Un écouteur de mise à jour empêche l'animation de s'exécuter potentiellement sur un thread distinct.
-
Remplacez la méthode
onAnimationUpdate()pour informer l'appelant de la modification de l'objet actuel. L'exemple de code suivant illustre l'utilisation globale deOnAnimationUpdateListener.
Kotlin
// Setting up a spring animation to animate the view1 and view2 translationX and translationY properties val (anim1X, anim1Y) = findViewById<View>(R.id.view1).let { view1 -> SpringAnimation(view1, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y) } val (anim2X, anim2Y) = findViewById<View>(R.id.view2).let { view2 -> SpringAnimation(view2, DynamicAnimation.TRANSLATION_X) to SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y) } // Registering the update listener anim1X.addUpdateListener { _, value, _ -> // Overriding the method to notify view2 about the change in the view1’s property. anim2X.animateToFinalPosition(value) } anim1Y.addUpdateListener { _, value, _ -> anim2Y.animateToFinalPosition(value) }
Java
// Creating two views to demonstrate the registration of the update listener. final View view1 = findViewById(R.id.view1); final View view2 = findViewById(R.id.view2); // Setting up a spring animation to animate the view1 and view2 translationX and translationY properties final SpringAnimation anim1X = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim1Y = new SpringAnimation(view1, DynamicAnimation.TRANSLATION_Y); final SpringAnimation anim2X = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_X); final SpringAnimation anim2Y = new SpringAnimation(view2, DynamicAnimation.TRANSLATION_Y); // Registering the update listener anim1X.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { // Overriding the method to notify view2 about the change in the view1’s property. @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2X.animateToFinalPosition(value); } }); anim1Y.addUpdateListener(new DynamicAnimation.OnAnimationUpdateListener() { @Override public void onAnimationUpdate(DynamicAnimation dynamicAnimation, float value, float velocity) { anim2Y.animateToFinalPosition(value); } });
OnAnimationEndListener
OnAnimationEndListener
notifie la fin d'une animation. Vous pouvez configurer l'écouteur pour qu'il reçoive un rappel chaque fois que l'animation atteint l'équilibre ou est annulée. Pour enregistrer l'écouteur, procédez comme suit :
-
Appelez la méthode
addEndListener()et associez l'écouteur à l'animation. -
Remplacez la méthode
onAnimationEnd()pour recevoir une notification chaque fois qu'une animation atteint l'équilibre ou est annulée.
Supprimer des écouteurs
Pour arrêter de recevoir les rappels de mise à jour et de fin d'animation, appelez respectivement les méthodes removeUpdateListener() et removeEndListener().
Définir la valeur de début de l'animation
Pour définir la valeur de début de l'animation, appelez la méthode setStartValue() et transmettez la valeur de début de l'animation. Si vous ne définissez pas de valeur de départ, l'animation utilise la valeur actuelle de la propriété de l'objet comme valeur de départ.
Définir la plage de valeurs de l'animation
Vous pouvez définir les valeurs minimale et maximale de l'animation lorsque vous souhaitez limiter la valeur de la propriété à une certaine plage. Il permet également de contrôler la plage si vous animez des propriétés qui ont une plage intrinsèque, comme l'alpha (de 0 à 1).
-
Pour définir la valeur minimale, appelez la méthode
setMinValue()et transmettez la valeur minimale de la propriété. -
Pour définir la valeur maximale, appelez la méthode
setMaxValue()et transmettez la valeur maximale de la propriété.
Les deux méthodes renvoient l'animation pour laquelle la valeur est définie.
Remarque : Si vous avez défini la valeur de départ et une plage de valeurs d'animation, assurez-vous que la valeur de départ se trouve dans la plage de valeurs minimale et maximale.
Définir la vitesse initiale
La vitesse de départ définit la vitesse à laquelle la propriété d'animation change au début de l'animation. La vitesse de départ par défaut est définie sur zéro pixel par seconde. Vous pouvez définir la vélocité avec la vélocité des gestes tactiles ou en utilisant une valeur fixe comme vélocité de départ. Si vous choisissez de fournir une valeur fixe, nous vous recommandons de la définir en dp par seconde, puis de la convertir en pixels par seconde. Définir la valeur en dp par seconde permet à la vitesse d'être indépendante de la densité et des facteurs de forme. Pour en savoir plus sur la conversion d'une valeur en pixels par seconde, consultez la section Conversion de dp par seconde en pixels par seconde.
Pour définir la vitesse, appelez la méthode
setStartVelocity()
et transmettez la vitesse en pixels par seconde. La méthode renvoie l'objet de force du ressort sur lequel la vitesse est définie.
Remarque : Utilisez les méthodes de classe GestureDetector.OnGestureListener ou VelocityTracker pour récupérer et calculer la vitesse des gestes tactiles.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000) val velocity = vt.yVelocity setStartVelocity(velocity) } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Compute velocity in the unit pixel/second vt.computeCurrentVelocity(1000); float velocity = vt.getYVelocity(); anim.setStartVelocity(velocity);
Convertir des dp par seconde en pixels par seconde
La vélocité d'un ressort doit être exprimée en pixels par seconde. Si vous choisissez de fournir une valeur fixe comme point de départ de la vitesse, indiquez la valeur en dp par seconde, puis convertissez-la en pixels par seconde. Pour la conversion, utilisez la méthode applyDimension() de la classe TypedValue. Reportez-vous à l'exemple de code suivant :
Kotlin
val pixelPerSecond: Float = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, resources.displayMetrics)
Java
float pixelPerSecond = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dpPerSecond, getResources().getDisplayMetrics());
Définir les propriétés du ressort
La classe SpringForce définit les méthodes getter et setter pour chacune des propriétés du ressort, telles que le coefficient d'amortissement et la rigidité. Pour définir les propriétés du ressort, il est important de récupérer l'objet de force du ressort ou de créer une force de ressort personnalisée sur laquelle vous pouvez définir les propriétés. Pour en savoir plus sur la création d'une force de ressort personnalisée, consultez la section Créer une force de ressort personnalisée.
Conseil : Lorsque vous utilisez les méthodes de définition, vous pouvez créer une chaîne de méthodes, car toutes les méthodes de définition renvoient l'objet de force du ressort.
Taux d'amortissement
Le coefficient d'amortissement décrit une réduction progressive de l'oscillation d'un ressort. En utilisant le rapport d'amortissement, vous pouvez définir la vitesse à laquelle les oscillations s'atténuent d'un rebond à l'autre. Il existe quatre façons différentes d'amortir un ressort :
- Un amortissement excessif se produit lorsque le taux d'amortissement est supérieur à un. Il permet à l'objet de revenir doucement à sa position de repos.
- L'amortissement critique se produit lorsque le rapport d'amortissement est égal à un. Elle permet à l'objet de revenir à la position de repos dans les plus brefs délais.
- Un amortissement insuffisant se produit lorsque le rapport d'amortissement est inférieur à un. Il permet à l'objet de dépasser plusieurs fois la position de repos en la dépassant, puis d'atteindre progressivement la position de repos.
- L'amortissement nul se produit lorsque le rapport d'amortissement est égal à zéro. Il permet à l'objet d'osciller indéfiniment.
Pour ajouter le coefficient d'amortissement au ressort, procédez comme suit :
-
Appelez la méthode
getSpring()pour récupérer le ressort auquel ajouter le taux d'amortissement. -
Appelez la méthode
setDampingRatio()et transmettez le coefficient d'amortissement que vous souhaitez ajouter au ressort. La méthode renvoie l'objet de force du ressort sur lequel le coefficient d'amortissement est défini.Remarque : Le coefficient d'amortissement doit être un nombre non négatif. Si vous définissez le taux d'amortissement sur zéro, le ressort n'atteindra jamais la position de repos. En d'autres termes, il oscille indéfiniment.
Les constantes de coefficient d'amortissement suivantes sont disponibles dans le système :
DAMPING_RATIO_HIGH_BOUNCYDAMPING_RATIO_MEDIUM_BOUNCYDAMPING_RATIO_LOW_BOUNCYDAMPING_RATIO_NO_BOUNCY
Figure 2 : Rebond élevé
Figure 3 : Rebond moyen
Figure 4 : Faible rebond
Figure 5 : Aucun rebond
Le taux d'amortissement par défaut est défini sur DAMPING_RATIO_MEDIUM_BOUNCY.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the damping ratio to create a low bouncing effect. spring.dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the damping ratio to create a low bouncing effect. anim.getSpring().setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY); …
Raideur
La raideur définit la constante du ressort, qui mesure sa résistance. Un ressort rigide applique plus de force à l'objet auquel il est attaché lorsque le ressort n'est pas au repos. Pour ajouter la rigidité au ressort, procédez comme suit :
-
Appelez la méthode
getSpring()pour récupérer le ressort auquel ajouter la rigidité. -
Appelez la méthode
setStiffness()et transmettez la valeur de rigidité que vous souhaitez ajouter au ressort. La méthode renvoie l'objet de force du ressort sur lequel la rigidité est définie.Remarque : La rigidité doit être un nombre positif.
Les constantes de rigidité suivantes sont disponibles dans le système :
Figure 6 : Raideur élevée
Figure 7 : raideur moyenne
Figure 8 : Raideur faible
Figure 9 : Raideur très faible
La rigidité par défaut est définie sur STIFFNESS_MEDIUM.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Setting the spring with a low stiffness. spring.stiffness = SpringForce.STIFFNESS_LOW … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Setting the spring with a low stiffness. anim.getSpring().setStiffness(SpringForce.STIFFNESS_LOW); …
Créer une force de ressort personnalisée
Vous pouvez créer une force de ressort personnalisée au lieu d'utiliser la force de ressort par défaut. La force de ressort personnalisée vous permet de partager la même instance de force de ressort sur plusieurs animations de ressort. Une fois la force du ressort créée, vous pouvez définir des propriétés telles que le coefficient d'amortissement et la rigidité.
-
Créer un objet
SpringForce.SpringForce force = new SpringForce(); -
Attribuez les propriétés en appelant les méthodes respectives. Vous pouvez également créer une chaîne de méthodes.
force.setDampingRatio(DAMPING_RATIO_LOW_BOUNCY).setStiffness(STIFFNESS_LOW); -
Appelez la méthode
setSpring()pour définir le ressort sur l'animation.setSpring(force);
Lancer l'animation
Il existe deux façons de démarrer une animation de rétroaction : en appelant la méthode start() ou la méthode animateToFinalPosition(). Les deux méthodes doivent être appelées sur le thread principal.
La méthode animateToFinalPosition() effectue deux tâches :
- Définit la position finale du ressort.
- Lance l'animation, si elle n'a pas encore commencé.
Étant donné que la méthode met à jour la position finale du ressort et démarre l'animation si nécessaire, vous pouvez l'appeler à tout moment pour modifier le cours d'une animation. Par exemple, dans une animation de rétroaction en chaîne, l'animation d'une vue dépend d'une autre vue. Pour une telle animation, il est plus pratique d'utiliser la méthode animateToFinalPosition(). En utilisant cette méthode dans une animation de rétroaction enchaînée, vous n'avez pas à vous soucier de savoir si l'animation que vous souhaitez mettre à jour ensuite est en cours d'exécution.
La figure 10 illustre une animation de rétroaction enchaînée, où l'animation d'une vue dépend d'une autre vue.
Pour utiliser la méthode animateToFinalPosition(), appelez la méthode animateToFinalPosition() et transmettez la position de repos du ressort. Vous pouvez également définir la position de repos du ressort en appelant la méthode setFinalPosition().
La méthode start() ne définit pas immédiatement la valeur de la propriété sur la valeur de départ. La valeur de la propriété change à chaque impulsion d'animation, ce qui se produit avant le passage du dessin.
Par conséquent, les modifications sont reflétées dans la frame suivante, comme si les valeurs étaient définies immédiatement.
Kotlin
findViewById<View>(R.id.imageView).also { img -> SpringAnimation(img, DynamicAnimation.TRANSLATION_Y).apply { … // Starting the animation start() … } }
Java
final View img = findViewById(R.id.imageView); final SpringAnimation anim = new SpringAnimation(img, DynamicAnimation.TRANSLATION_Y); … // Starting the animation anim.start(); …
Annuler l'animation
Vous pouvez annuler l'animation ou passer à la fin. Une situation idéale où vous devez annuler ou passer à la fin de l'animation se produit lorsqu'une interaction de l'utilisateur exige que l'animation soit arrêtée immédiatement. Cela se produit principalement lorsqu'un utilisateur quitte une application de manière abrupte ou que la vue devient invisible.
Vous pouvez arrêter l'animation de deux manières.
La méthode cancel() met fin à l'animation à la valeur où elle se trouve. La méthode skipToEnd() permet de passer l'animation à la valeur finale, puis d'y mettre fin.
Avant de pouvoir mettre fin à l'animation, il est important de vérifier l'état du ressort. Si l'état n'est pas amorti, l'animation ne peut jamais atteindre la position de repos.
Pour vérifier l'état du ressort, appelez la méthode canSkipToEnd(). Si le ressort est amorti, la méthode renvoie true, sinon false.
Une fois que vous connaissez l'état du ressort, vous pouvez mettre fin à une animation en utilisant la méthode skipToEnd() ou la méthode cancel(). La méthode cancel() doit être appelée uniquement sur le thread principal.
Remarque : En règle générale, la méthode skipToEnd() provoque un saut visuel.