Spring Animation est une technique d'animation qui simule le comportement physique d'un ressort : masse, raideur (stiffness), amortissement (damping) et vitesse initiale. Contrairement aux interpolations linéaires et aux courbes de Bézier, l'animation à ressort crée un mouvement naturel avec un effet d'oscillation amortie qui semble organique sur n'importe quel appareil. Selon les Material Design Guidelines (2026), Spring Animation est utilisée dans 73% des interfaces animées des 100 meilleures applications de l'App Store. En savoir plus sur les autres types d'animation dans le guide général d'animation.
Points clés
Spring Animation est une animation dont le mouvement est décrit par l'équation de l'oscillateur harmonique amorti. Au lieu d'interpoler une valeur de 0 à 1 pendant un temps fixe, Spring Animation calcule la position de l'objet à chaque instant en fonction de paramètres physiques : masse, raideur, amortissement et vitesse initiale. Le résultat est un mouvement naturel et organique qui ne semble pas « mécanique ».
Contrairement aux courbes Easing (easeIn, easeOut, cubic-bezier), où la durée est fixe et la trajectoire prédéterminée, Spring Animation s'adapte dynamiquement : si la valeur cible change pendant l'animation, le ressort recalcule en douceur la trajectoire à partir de la position actuelle. Ceci est particulièrement important pour les animations qui peuvent être interrompues — drag-to-dismiss, pull-to-refresh, cartes glissables (swipeable cards).
Selon Apple WWDC 2025, l'utilisation de l'animation à ressort au lieu de courbes fixes réduit la latence perçue de 30 à 50 % grâce à l'accélération naturelle au début et à la décélération douce à la fin. Spring Animation est recommandée pour toute animation liée au mouvement : déplacement, mise à l'échelle, apparition/disparition.
Le comportement du ressort est défini par quatre paramètres. Stiffness (raideur) est la force de rappel vers l'équilibre : une valeur de 100–300 donne un ressort souple pour les listes, 500–1000 donne un ressort rigide pour les boutons et interrupteurs. Damping (amortissement) est la résistance au mouvement : 0 — oscillations infinies, 0.1–0.5 — oscillations amorties notables (effet de rebond), 1 — amortissement critique (sans oscillations, décélération douce).
| Paramètre | Plage | Effet | Exemple d'utilisation |
|---|---|---|---|
| Stiffness | 100–1000 | Vitesse de retour à l'équilibre | 200 = liste, 600 = bouton |
| Damping | 0.0–1.0 | Amortissement des oscillations | 0.3 = rebond, 1.0 = sans oscillations |
| Mass | 0.1–10.0 | Inertie de l'objet | 1.0 = standard, 3.0 = élément lourd |
| Initial Velocity | Quelconque | Vitesse initiale en pixels/s | Vitesse du doigt lors du drag-to-dismiss |
Amortissement critique (damping = 1.0) est le mode optimal pour la plupart des animations d'interface : l'objet retourne à la position cible aussi rapidement que possible sans dépassement. Pour l'effet de rebond (par exemple, pull-to-refresh), utilisez damping = 0.3–0.5. Pour l'apparition de fenêtres modales — damping = 0.6–0.8 avec stiffness = 300–500. La masse est rarement modifiée — la valeur standard de 1.0 convient à presque tous les cas.
Sur iOS, Spring Animation est disponible via UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) depuis iOS 7 et CASpringAnimation (Core Animation) depuis iOS 9. La version UIView est plus simple et plus populaire pour animer les propriétés de View (transform, alpha, center). CASpringAnimation est plus précise et donne accès à stiffness, damping et mass en tant que propriétés séparées.
import UIKit
// UIView.animate avec paramètres de ressort
let originalCenter = view.center
UIView.animate(
withDuration: 0.8,
delay: 0,
usingSpringWithDamping: 0.5,
initialSpringVelocity: 0.3,
options: [.curveEaseInOut, .allowUserInteraction]
) {
view.center = CGPoint(x: originalCenter.x + 100, y: originalCenter.y)
view.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
} completion: { _ in
UIView.animate(withDuration: 0.3) {
view.transform = .identity
}
}
// CASpringAnimation — contrôle précis des paramètres
let spring = CASpringAnimation()
spring.keyPath = "transform.scale"
spring.fromValue = 1.0
spring.toValue = 1.5
spring.stiffness = 300
spring.damping = 10
spring.mass = 1.0
spring.initialVelocity = 5.0
"> CASpringAnimation.settlingDuration — durée calculée
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")
CASpringAnimation.settlingDuration est une propriété unique de Core Animation qui calcule la durée minimale d'animation nécessaire pour que le ressort atteigne l'équilibre. Cela signifie que vous n'avez pas besoin de choisir la durée manuellement — le système détermine lui-même le temps nécessaire à l'amortissement des oscillations. Pour UIView.animate, la durée est définie explicitement, et un damping de 0.3–0.7 produit un effet de rebond notable. Pour l'intégration avec UIPanGestureRecognizer, passez velocityRecognizer.velocity(in: view) comme initialSpringVelocity — ainsi l'animation continue le mouvement du doigt à la même vitesse.
Sur Android, SpringAnimation fait partie de la bibliothèque AndroidX Dynamic Animation (androidx.dynamicanimation). La classe principale est SpringAnimation, qui anime toute propriété float d'une View ou d'un objet personnalisé. Les paramètres sont définis via SpringForce — stiffness (par défaut STIFFNESS_MEDIUM = 600) et dampingRatio (par défaut DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).
// build.gradle.kts
implementation("androidx.dynamicanimation:dynamicanimation:1.1.0")
// Kotlin : SpringAnimation avec SpringForce personnalisé
import androidx.dynamicanimation.animation.SpringAnimation
import androidx.dynamicanimation.animation.SpringForce
import androidx.dynamicanimation.animation.FloatPropertyCompat
val springAnim = SpringAnimation(myView, SpringAnimation.TRANSLATION_X).apply {
spring = SpringForce().apply {
stiffness = SpringForce.STIFFNESS_LOW // 200.0f
dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY // 0.2f
finalPosition = 300f
}
start()
}
// SpringAnimation avec vitesse initiale depuis le geste
myView.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
springAnim.cancel()
false
}
MotionEvent.ACTION_UP -> {
val velocity = velocityTracker?.getXVelocity() ?: 0f
SpringAnimation(myView, SpringAnimation.TRANSLATION_X).apply {
spring = SpringForce(0f) "> Retour à la position d'origine
setStartVelocity(velocity)
start()
}
true
}
else -> false
}
}
"> SpringAnimation pour une propriété personnalisée
val customAnim = SpringAnimation(
myObject,
object : FloatPropertyCompat<MyClass>("progress") {
override fun getValue(obj: MyClass): Float = obj.progress
override fun setValue(obj: MyClass, value: Float) { obj.progress = value }
}
).apply { start() }
Constantes SpringForce : STIFFNESS_LOW (200), STIFFNESS_MEDIUM (600), STIFFNESS_HIGH (1800) ; DAMPING_RATIO_HIGH_BOUNCY (0.2), DAMPING_RATIO_MEDIUM_BOUNCY (0.5), DAMPING_RATIO_LOW_BOUNCY (0.75), DAMPING_RATIO_NO_BOUNCY (1.0). Pour RecyclerView avec animation d'éléments, utilisez SpringAnimation avec DynamicAnimation.OnAnimationEndListener pour libérer les ressources. Pour animer plusieurs propriétés, utilisez SpringAnimation.createFor(view, property).
Jetpack Compose : à partir de Compose 1.0, l'animation à ressort est disponible via Animatable avec spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). C'est l'approche préférée pour les projets Compose, car SpringAnimation de DynamicAnimation n'est compatible qu'avec le système View. La version Compose de spring utilise le même moteur physique mais fonctionne dans le contexte du Compose Animation System, se mettant automatiquement en pause lors du détachement.
Spring Animation et les courbes Easing (easeInOut, FastOutSlowIn, decelerate) résolvent des problèmes différents. Les courbes Easing sont des trajectoires mathématiquement définies avec un temps fixe. Spring est une simulation physique où le temps dépend des paramètres et des conditions initiales. Pour les animations simples d'apparition/disparition, les courbes Easing suffisent. Pour les animations liées au mouvement de l'utilisateur (drag, swipe, scroll), Spring Animation offre une réponse plus naturelle.
| Scénario | Recommandation | Paramètres |
|---|---|---|
| Apparition d'élément | Spring (damping = 0.7, stiffness = 400) | Apparition douce avec léger dépassement |
| Swipe-to-dismiss | Spring + vitesse initiale | setStartVelocity(velocity), damping = 0.5 |
| Animation d'icône | Spring (damping = 0.3, stiffness = 600) | Rebond notable pour les effets d'accent |
| Physique de scroll | Spring (système) | Ne pas personnaliser — Android gère |
| Changement de taille | Easing (FastOutSlowIn) | Easing plus fiable pour les changements de layout |
Anti-patrons : n'utilisez pas Spring Animation pour animer les paramètres de layout (largeur/hauteur de View via LayoutParams) — cela provoque un recalcul de hiérarchie à chaque image, entraînant des saccades et des chutes de FPS. Pour l'animation de couleur, les courbes Easing sont également préférables. Pour l'animation de la position de scroll, utilisez le Scroller système avec fling — Spring Animation n'offre aucun avantage ici. Pour des performances maximales sur Android, limitez le nombre d'instances SpringAnimation actives simultanément à 10–15.
Foire aux questions
Stiffness est la raideur du ressort (force de rappel). Une valeur élevée (1000) produit un mouvement rapide et brusque. Une valeur faible (100) produit un mouvement doux et lent. Damping est la résistance au mouvement. Une valeur faible (0.2) produit de longues oscillations avec rebond. Une valeur élevée (1.0) produit une absence d'oscillations, une décélération douce. Stiffness détermine la vitesse, damping détermine la présence et l'intensité des oscillations.
Commencez avec damping = 0.5 et stiffness = 400 — c'est un ensemble de départ universel pour iOS et Android. Pour l'apparition d'éléments, augmentez damping à 0.7. Pour les effets d'accent (j'aime, ajouter au panier), réduisez damping à 0.3 avec stiffness = 600. Pour Material Motion, utilisez damping = 0.6 et stiffness = 300. Testez l'animation sur un appareil réel, pas sur un simulateur.
Oui, dans SwiftUI l'animation à ressort est configurée via .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) ou .spring(blendDuration: 0.3) dans withAnimation. Les paramètres response et dampingFraction reflètent stiffness et damping d'UIKit. Pour les animations de glissement interactives, utilisez .interactiveSpring() — une version spéciale avec vitesse initiale pilotée par le geste optimisée pour les animations de glissement.
Vérifiez SpringForce.finalPosition — s'il n'est pas défini ou égal à la valeur actuelle, l'animation peut ne pas démarrer. Appelez springAnim.cancel() dans onPause() de l'Activity/Fragment. Pour SpringAnimation dans RecyclerView, utilisez view.setOnDetachListener { animator.cancel() }. Pour Jetpack Compose, SpringAnimation se met automatiquement en pause lors des changements de composition.
Oui. Sur iOS, appelez view.layer.removeAnimation(forKey:) — l'animation s'arrête à l'image actuelle. Sur Android, appelez springAnim.cancel() — l'objet reste à la position actuelle. Pour une transition en douceur vers une nouvelle valeur cible, mettez à jour finalPosition et n'appelez pas cancel — SpringAnimation recalcule automatiquement la trajectoire. Pour SkipToEnd, utilisez springAnim.skipToEnd() sur Android.
Résumé
Nous développerons une application mobile clé en main
IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.
Lisez aussi