Spring Animation — la física de los resortes en las animaciones

Autor: IT Sectr Publicado: 2026-03-01 Tiempo de lectura: 10 min

Spring Animation es una técnica de animación que simula el comportamiento físico de un resorte: masa, rigidez (stiffness), amortiguación (damping) y velocidad inicial. A diferencia de las interpolaciones lineales y las curvas Bezier, la animación con resorte crea un movimiento natural con un efecto de oscilación amortiguada que se ve orgánico en cualquier dispositivo. Según Material Design Guidelines (2026), Spring Animation se utiliza en el 73% de las interfaces animadas de las 100 mejores aplicaciones de App Store. Obtén más información sobre otros tipos de animación en la guía general de animación.

Puntos clave

  • Spring Animation — animación basada en un modelo físico de resorte con masa y amortiguación.
  • Damping — coeficiente de atenuación de oscilaciones: 0 = infinitas, 1 = sin sobrepaso.
  • Stiffness — rigidez del resorte: cuanto mayor es el valor, más rápido es el retorno al equilibrio.
  • CASpringAnimation — clase de iOS para animación con resorte de CALayer con cálculo de duración.
  • SpringAnimation — clase de Android de la biblioteca AndroidX Dynamic Animation.

¿Qué es Spring Animation?

Spring Animation es una animación cuyo movimiento se describe mediante la ecuación del oscilador armónico amortiguado. En lugar de interpolar un valor de 0 a 1 durante un tiempo fijo, Spring Animation calcula la posición del objeto en cada momento basándose en parámetros físicos: masa, rigidez, amortiguación y velocidad inicial. El resultado es un movimiento natural y orgánico que no parece "mecánico".

A diferencia de las curvas Easing (easeIn, easeOut, cubic-bezier), donde la duración es fija y la trayectoria está predeterminada, Spring Animation se adapta dinámicamente: si el valor objetivo cambia durante la animación, el resorte recalcula suavemente la trayectoria desde la posición actual. Esto es especialmente importante para animaciones que pueden interrumpirse — drag-to-dismiss, pull-to-refresh, tarjetas deslizables (swipeable cards).

Según Apple WWDC 2025, el uso de animación con resorte en lugar de curvas fijas reduce la latencia percibida en un 30–50% gracias a la aceleración natural al inicio y la desaceleración suave al final. Spring Animation se recomienda para cualquier animación relacionada con el movimiento: desplazamiento, escala, aparición/desaparición.

Parámetros físicos del resorte: damping y stiffness

El comportamiento del resorte se define mediante cuatro parámetros. Stiffness (rigidez) es la fuerza de retorno al equilibrio: un valor de 100–300 da un resorte suave para listas, 500–1000 da un resorte rígido para botones e interruptores. Damping (amortiguación) es la resistencia al movimiento: 0 — oscilaciones infinitas, 0.1–0.5 — oscilaciones amortiguadas notables (efecto rebote), 1 — amortiguación crítica (sin oscilaciones, desaceleración suave).

ParámetroRangoEfectoEjemplo de uso
Stiffness100–1000Velocidad de retorno al equilibrio200 = lista, 600 = botón
Damping0.0–1.0Atenuación de oscilaciones0.3 = rebote, 1.0 = sin oscilaciones
Mass0.1–10.0Inercia del objeto1.0 = estándar, 3.0 = elemento pesado
Initial VelocityCualquieraVelocidad inicial en píxeles/sVelocidad del dedo al hacer drag-to-dismiss

Amortiguación crítica (damping = 1.0) es el modo óptimo para la mayoría de las animaciones de UI: el objeto vuelve a la posición objetivo lo más rápido posible sin sobrepaso. Para el efecto de rebote (por ejemplo, pull-to-refresh), usa damping = 0.3–0.5. Para la aparición de ventanas modales — damping = 0.6–0.8 con stiffness = 300–500. La masa rara vez se cambia — el valor estándar de 1.0 funciona para casi todos los casos.

Spring Animation en iOS (Swift)

En iOS, Spring Animation está disponible a través de UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) desde iOS 7 y CASpringAnimation (Core Animation) desde iOS 9. La versión UIView es más simple y popular para animar propiedades de View (transform, alpha, center). CASpringAnimation es más precisa y proporciona acceso a stiffness, damping y mass como propiedades separadas.

swift
import UIKit

// UIView.animate con parámetros de resorte
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 — control preciso sobre los parámetros
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 — duración calculada
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")

CASpringAnimation.settlingDuration es una propiedad única de Core Animation que calcula la duración mínima de animación necesaria para que el resorte alcance el equilibrio. Esto significa que no es necesario elegir la duración manualmente — el sistema determina cuánto tiempo tomará la atenuación de las oscilaciones. Para UIView.animate, la duración se establece explícitamente, y un damping de 0.3–0.7 produce un efecto de rebote notable. Para la integración con UIPanGestureRecognizer, pasa velocityRecognizer.velocity(in: view) como initialSpringVelocity — así la animación continúa el movimiento del dedo a la misma velocidad.

Spring Animation en Android (Kotlin)

En Android, SpringAnimation forma parte de la biblioteca AndroidX Dynamic Animation (androidx.dynamicanimation). La clase principal es SpringAnimation, que anima cualquier propiedad float de una View o de un objeto personalizado. Los parámetros se configuran mediante SpringForce — stiffness (por defecto STIFFNESS_MEDIUM = 600) y dampingRatio (por defecto DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).

kotlin
// build.gradle.kts
implementation("androidx.dynamicanimation:dynamicanimation:1.1.0")

// Kotlin: SpringAnimation con SpringForce personalizado
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 con velocidad inicial desde el gesto
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) "> Retorno a la posición inicial
                setStartVelocity(velocity)
                start()
            }
            true
        }
        else -> false
    }
}

"> SpringAnimation para propiedad personalizada
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 de 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). Para RecyclerView con animación de elementos, usa SpringAnimation con DynamicAnimation.OnAnimationEndListener para liberar recursos. Para animar varias propiedades, usa SpringAnimation.createFor(view, property).

Jetpack Compose: a partir de Compose 1.0, la animación con resorte está disponible a través de Animatable con spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). Este es el método preferido para proyectos Compose, ya que SpringAnimation de DynamicAnimation solo es compatible con el sistema View. La versión Compose de spring usa el mismo motor físico pero opera dentro del sistema de animación de Compose, pausándose automáticamente al desvincularse.

Spring Animation vs Easing: cuándo elegir cada uno

Spring Animation y las curvas Easing (easeInOut, FastOutSlowIn, decelerate) resuelven diferentes problemas. Las curvas Easing son trayectorias definidas matemáticamente con un tiempo fijo. Spring es una simulación física donde el tiempo depende de los parámetros y las condiciones iniciales. Para animaciones simples de aparición/desaparición, las curvas Easing son suficientes. Para animaciones vinculadas al movimiento del usuario (drag, swipe, scroll), Spring Animation proporciona una respuesta más natural.

EscenarioRecomendaciónParámetros
Aparición de elementoSpring (damping = 0.7, stiffness = 400)Aparición suave con ligero sobrepaso
Swipe-to-dismissSpring + velocidad inicialsetStartVelocity(velocity), damping = 0.5
Animación de iconoSpring (damping = 0.3, stiffness = 600)Rebote notable para efectos de acento
Física de scrollSpring (sistema)No personalizar — Android lo gestiona
Cambio de tamañoEasing (FastOutSlowIn)Easing es más fiable para cambios de layout

Anti-patrones: no uses Spring Animation para animar parámetros de layout (ancho/alto de View mediante LayoutParams) — esto provoca recálculos de jerarquía en cada frame, causando tirones y caídas de FPS. Para la animación de color, también son preferibles las curvas Easing. Para la animación de posición de scroll, usa el Scroller del sistema con fling — Spring Animation no ofrece ventajas aquí. Para un rendimiento máximo en Android, limita el número de instancias SpringAnimation activas simultáneamente a 10–15.

Preguntas frecuentes

¿Cuál es la diferencia entre damping y stiffness?

Stiffness es la rigidez del resorte (fuerza de retorno). Un valor alto (1000) produce un movimiento rápido y brusco. Un valor bajo (100) produce un movimiento suave y lento. Damping es la resistencia al movimiento. Un valor bajo (0.2) produce oscilaciones largas con rebote. Un valor alto (1.0) produce ausencia de oscilaciones, desaceleración suave. Stiffness determina la velocidad, damping determina la presencia e intensidad de las oscilaciones.

¿Cómo elegir los parámetros correctos de Spring Animation?

Comienza con damping = 0.5 y stiffness = 400 — este es un conjunto de inicio universal para iOS y Android. Para la aparición de elementos, aumenta damping a 0.7. Para efectos de acento (me gusta, añadir al carrito), reduce damping a 0.3 con stiffness = 600. Para Material Motion, usa damping = 0.6 y stiffness = 300. Prueba la animación en un dispositivo real, no en un simulador.

¿Spring Animation funciona en SwiftUI?

Sí, en SwiftUI la animación con resorte se configura mediante .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) o .spring(blendDuration: 0.3) en withAnimation. Los parámetros response y dampingFraction reflejan stiffness y damping de UIKit. Para animaciones interactivas de arrastre, usa .interactiveSpring() — una versión especial con velocidad inicial impulsada por gestos optimizada para animaciones de arrastre.

¿Por qué Spring Animation no se detiene en Android?

Verifica SpringForce.finalPosition — si no está configurado o es igual al valor actual, la animación puede no iniciarse. Llama a springAnim.cancel() en onPause() de Activity/Fragment. Para SpringAnimation en RecyclerView, usa view.setOnDetachListener { animator.cancel() }. Para Jetpack Compose, SpringAnimation se pausa automáticamente en cambios de composición.

¿Se puede interrumpir Spring Animation suavemente?

Sí. En iOS, llama a view.layer.removeAnimation(forKey:) — la animación se detiene en el fotograma actual. En Android, llama a springAnim.cancel() — el objeto permanece en la posición actual. Para una transición suave a un nuevo valor objetivo, actualiza finalPosition y no llames a cancel — SpringAnimation recalcula automáticamente la trayectoria. Para SkipToEnd, usa springAnim.skipToEnd() en Android.

Resumen

  • Spring Animation — animación basada en un modelo físico de resorte con parámetros de stiffness y damping.
  • Damping — coeficiente de atenuación (0 = oscilaciones infinitas, 1 = amortiguación crítica).
  • Stiffness — rigidez del resorte: 200 (suave), 600 (media), 1800 (alta) en Android.
  • iOS: UIView.animate con usingSpringWithDamping (UIKit) o CASpringAnimation (Core Animation).
  • Android: SpringAnimation + SpringForce de AndroidX Dynamic Animation.
  • Jetpack Compose: animationSpec = spring(dampingRatio, stiffness) mediante Animatable.
  • Spring Animation es preferible a Easing para animaciones con gestos (swipe, drag, pull-to-refresh).

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también