Spring Animation — a física da mola nas animações

Autor: IT Sectr Publicado: 2026-03-01 Tempo de leitura: 10 min

Spring Animation é uma técnica de animação que simula o comportamento físico de uma mola: massa, rigidez (stiffness), amortecimento (damping) e velocidade inicial. Diferente das interpolações lineares e curvas Bezier, a animação com mola cria um movimento natural com um efeito de oscilação amortecida que parece orgânico em qualquer dispositivo. De acordo com as Material Design Guidelines (2026), a Spring Animation é usada em 73% das interfaces animadas dos top 100 aplicativos da App Store. Saiba mais sobre outros tipos de animação no guia geral de animação.

Pontos principais

  • Spring Animation — animação baseada em um modelo físico de mola com massa e amortecimento.
  • Damping — coeficiente de amortecimento de oscilações: 0 = infinitas, 1 = sem ultrapassagem.
  • Stiffness — rigidez da mola: quanto maior o valor, mais rápido o retorno ao equilíbrio.
  • CASpringAnimation — classe iOS para animação com mola de CALayer com cálculo de duração.
  • SpringAnimation — classe Android da biblioteca AndroidX Dynamic Animation.

O que é Spring Animation?

Spring Animation é uma animação cujo movimento é descrito pela equação do oscilador harmônico amortecido. Em vez de interpolar um valor de 0 a 1 durante um tempo fixo, a Spring Animation calcula a posição do objeto em cada momento com base em parâmetros físicos: massa, rigidez, amortecimento e velocidade inicial. O resultado é um movimento natural e orgânico que não parece "mecânico".

Ao contrário das curvas Easing (easeIn, easeOut, cubic-bezier), onde a duração é fixa e a trajetória é predeterminada, a Spring Animation se adapta dinamicamente: se o valor alvo mudar durante a animação, a mola recalcula suavemente a trajetória a partir da posição atual. Isso é especialmente importante para animações que podem ser interrompidas — drag-to-dismiss, pull-to-refresh, cartões deslizáveis (swipeable cards).

De acordo com a Apple WWDC 2025, o uso de animação com mola em vez de curvas fixas reduz a latência percebida em 30–50% graças à aceleração natural no início e à desaceleração suave no final. A Spring Animation é recomendada para qualquer animação relacionada a movimento: deslocamento, escala, aparecimento/desaparecimento.

Parâmetros físicos da mola: damping e stiffness

O comportamento da mola é definido por quatro parâmetros. Stiffness (rigidez) é a força de retorno ao equilíbrio: um valor de 100–300 dá uma mola suave para listas, 500–1000 dá uma mola rígida para botões e interruptores. Damping (amortecimento) é a resistência ao movimento: 0 — oscilações infinitas, 0.1–0.5 — oscilações amortecidas perceptíveis (efeito de ricochete), 1 — amortecimento crítico (sem oscilações, desaceleração suave).

ParâmetroFaixaEfeitoExemplo de uso
Stiffness100–1000Velocidade de retorno ao equilíbrio200 = lista, 600 = botão
Damping0.0–1.0Amortecimento de oscilações0.3 = ricochete, 1.0 = sem oscilações
Mass0.1–10.0Inércia do objeto1.0 = padrão, 3.0 = elemento pesado
Initial VelocityQualquerVelocidade inicial em pixels/sVelocidade do dedo ao fazer drag-to-dismiss

Amortecimento crítico (damping = 1.0) é o modo ideal para a maioria das animações de UI: o objeto retorna à posição alvo o mais rápido possível sem ultrapassagem. Para o efeito de ricochete (por exemplo, pull-to-refresh), use damping = 0.3–0.5. Para aparecimento de janelas modais — damping = 0.6–0.8 com stiffness = 300–500. A massa raramente é alterada — o valor padrão de 1.0 funciona para quase todos os casos.

Spring Animation no iOS (Swift)

No iOS, a Spring Animation está disponível através de UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) desde o iOS 7 e CASpringAnimation (Core Animation) desde o iOS 9. A versão UIView é mais simples e popular para animar propriedades de View (transform, alpha, center). A CASpringAnimation é mais precisa e fornece acesso a stiffness, damping e mass como propriedades separadas.

swift
import UIKit

// UIView.animate com parâmetros de mola
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 — controle preciso sobre os 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 — duração calculada
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")

CASpringAnimation.settlingDuration é uma propriedade única da Core Animation que calcula a duração mínima de animação necessária para a mola atingir o equilíbrio. Isso significa que você não precisa escolher a duração manualmente — o sistema determina quanto tempo o amortecimento das oscilações levará. Para UIView.animate, a duração é definida explicitamente, e um damping de 0.3–0.7 produz um efeito de ricochete perceptível. Para integração com UIPanGestureRecognizer, passe velocityRecognizer.velocity(in: view) como initialSpringVelocity — assim a animação continua o movimento do dedo na mesma velocidade.

Spring Animation no Android (Kotlin)

No Android, a SpringAnimation faz parte da biblioteca AndroidX Dynamic Animation (androidx.dynamicanimation). A classe principal é SpringAnimation, que anima qualquer propriedade float de uma View ou de um objeto personalizado. Os parâmetros são configurados através de SpringForce — stiffness (padrão STIFFNESS_MEDIUM = 600) e dampingRatio (padrão DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).

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

// Kotlin: SpringAnimation com 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 com velocidade inicial do 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 à posição inicial
                setStartVelocity(velocity)
                start()
            }
            true
        }
        else -> false
    }
}

"> SpringAnimation para propriedade 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 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 com animação de itens, use SpringAnimation com DynamicAnimation.OnAnimationEndListener para liberar recursos. Para animar várias propriedades, use SpringAnimation.createFor(view, property).

Jetpack Compose: a partir do Compose 1.0, a animação com mola está disponível através de Animatable com spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). Esta é a abordagem preferida para projetos Compose, já que SpringAnimation do DynamicAnimation é compatível apenas com o sistema View. A versão Compose do spring usa o mesmo motor físico, mas opera no contexto do Compose Animation System, pausando automaticamente ao ser desanexado.

Spring Animation vs Easing: quando escolher cada um

Spring Animation e curvas Easing (easeInOut, FastOutSlowIn, decelerate) resolvem problemas diferentes. Curvas Easing são trajetórias matematicamente definidas com tempo fixo. Spring é uma simulação física onde o tempo depende dos parâmetros e condições iniciais. Para animações simples de aparecimento/desaparecimento, curvas Easing são suficientes. Para animações ligadas ao movimento do usuário (drag, swipe, scroll), a Spring Animation fornece uma resposta mais natural.

CenárioRecomendaçãoParâmetros
Aparecimento de elementoSpring (damping = 0.7, stiffness = 400)Aparecimento suave com ligeira ultrapassagem
Swipe-to-dismissSpring + velocidade inicialsetStartVelocity(velocity), damping = 0.5
Animação de íconeSpring (damping = 0.3, stiffness = 600)Ricochete perceptível para efeitos de destaque
Física de scrollSpring (sistema)Não personalizar — Android gerencia
Alteração de tamanhoEasing (FastOutSlowIn)Easing é mais confiável para mudanças de layout

Anti-padrões: não use Spring Animation para animar parâmetros de layout (largura/altura de View via LayoutParams) — isso causa recálculo de hierarquia em cada quadro, levando a travamentos e quedas de FPS. Para animação de cor, curvas Easing também são preferíveis. Para animação de posição de scroll, use o Scroller do sistema com fling — Spring Animation não oferece vantagens aqui. Para máximo desempenho no Android, limite o número de instâncias SpringAnimation ativas simultaneamente a 10–15.

Perguntas frequentes

Qual a diferença entre damping e stiffness?

Stiffness é a rigidez da mola (força de retorno). Um valor alto (1000) produz movimento rápido e brusco. Um valor baixo (100) produz movimento suave e lento. Damping é a resistência ao movimento. Um valor baixo (0.2) produz oscilações longas com ricochete. Um valor alto (1.0) produz ausência de oscilações, desaceleração suave. Stiffness determina a velocidade, damping determina a presença e intensidade das oscilações.

Como escolher os parâmetros corretos da Spring Animation?

Comece com damping = 0.5 e stiffness = 400 — este é um conjunto inicial universal para iOS e Android. Para aparecimento de elementos, aumente damping para 0.7. Para efeitos de destaque (curtir, adicionar ao carrinho), reduza damping para 0.3 com stiffness = 600. Para Material Motion, use damping = 0.6 e stiffness = 300. Teste a animação em um dispositivo real, não em um simulador.

Spring Animation funciona no SwiftUI?

Sim, no SwiftUI a animação com mola é configurada através de .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) ou .spring(blendDuration: 0.3) no withAnimation. Os parâmetros response e dampingFraction refletem stiffness e damping do UIKit. Para animações de arrasto interativas, use .interactiveSpring() — uma versão especial com velocidade inicial orientada por gestos otimizada para animações de arrasto.

Por que a Spring Animation não para no Android?

Verifique SpringForce.finalPosition — se não estiver definido ou for igual ao valor atual, a animação pode não iniciar. Chame springAnim.cancel() no onPause() da Activity/Fragment. Para SpringAnimation em RecyclerView, use view.setOnDetachListener { animator.cancel() }. Para Jetpack Compose, a SpringAnimation pausa automaticamente em mudanças de composição.

Posso interromper a Spring Animation suavemente?

Sim. No iOS, chame view.layer.removeAnimation(forKey:) — a animação para no quadro atual. No Android, chame springAnim.cancel() — o objeto permanece na posição atual. Para uma transição suave para um novo valor alvo, atualize finalPosition e não chame cancel — a SpringAnimation recalcula automaticamente a trajetória. Para SkipToEnd, use springAnim.skipToEnd() no Android.

Resumo

  • Spring Animation — animação baseada em um modelo físico de mola com parâmetros de stiffness e damping.
  • Damping — coeficiente de amortecimento (0 = oscilações infinitas, 1 = amortecimento crítico).
  • Stiffness — rigidez da mola: 200 (suave), 600 (médio), 1800 (alto) no Android.
  • iOS: UIView.animate com usingSpringWithDamping (UIKit) ou CASpringAnimation (Core Animation).
  • Android: SpringAnimation + SpringForce da AndroidX Dynamic Animation.
  • Jetpack Compose: animationSpec = spring(dampingRatio, stiffness) através de Animatable.
  • Spring Animation é preferível a Easing para animações com gestos (swipe, drag, pull-to-refresh).

Vamos desenvolver um aplicativo móvel chave na mão

A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.

Discutir o projeto

Leia também