Spring Animation — istota, fizyka sprężyny w animacjach

Autor: IT Sectr Opublikowano: 2026-03-01 Czas czytania: 10 min

Spring Animation — technika animacji modelująca fizyczne zachowanie sprężyny: masa, sztywność (stiffness), tłumienie (damping) i prędkość początkowa. W przeciwieństwie do interpolacji liniowych i krzywych Béziera, animacja sprężynowa tworzy naturalny ruch z efektem tłumionych oscylacji, który wygląda organicznie na każdym urządzeniu. Według Material Design Guidelines (2026), Spring Animation jest używana w 73% animowanych interfejsów w top 100 aplikacji App Store. Więcej o innych rodzajach animacji przeczytasz w ogólnym przewodniku po animacji.

Najważniejsze

  • Spring Animation — animacja oparta na fizycznym modelu sprężyny z masą i tłumieniem.
  • Damping — współczynnik tłumienia oscylacji: 0 = nieskończone, 1 = bez przeregulowania.
  • Stiffness — sztywność sprężyny: im wyższa, tym szybszy powrót do równowagi.
  • CASpringAnimation — klasa iOS do animacji sprężynowej CALayer z obliczaniem czasu trwania.
  • SpringAnimation — klasa Androida z biblioteki AndroidX Dynamic Animation.

Czym jest Spring Animation?

Spring Animation — to animacja, której ruch opisuje równanie oscylatora harmonicznego z tłumieniem. Zamiast interpolować wartość od 0 do 1 w ustalonym czasie, Spring Animation oblicza pozycję obiektu w każdej chwili na podstawie parametrów fizycznych: masa (mass), sztywność (stiffness), tłumienie (damping) i prędkość początkowa (initialVelocity). Rezultat — naturalny, organiczny ruch, który nie wygląda „mechanicznie".

W przeciwieństwie do krzywych Easing (easeIn, easeOut, cubic-bezier), gdzie czas trwania jest stały a trajektoria z góry określona, Spring Animation dynamicznie się dostosowuje: jeśli zmienisz wartość docelową podczas animacji, sprężyna płynnie przeliczy trajektorię od bieżącej pozycji. Jest to szczególnie ważne w przypadku animacji, które mogą być przerywane — drag-to-dismiss, pull-to-refresh, karty do przesuwania (swipeable cards).

Według Apple WWDC 2025, użycie animacji sprężynowej zamiast stałych krzywych zmniejsza odczuwalne opóźnienie (perceived latency) o 30–50% dzięki naturalnemu przyspieszeniu na początku i płynnemu zwalnianiu na końcu. Spring Animation jest zalecana do wszelkich animacji związanych z ruchem: przesuwanie, skalowanie, pojawianie/znikanie.

Parametry fizyczne sprężyny: damping i stiffness

Zachowanie sprężyny określają cztery parametry. Stiffness (sztywność) — siła powrotu do równowagi: wartość 100–300 daje miękką sprężynę dla list, 500–1000 — twardą dla przycisków i przełączników. Damping (tłumienie) — opór ruchu: 0 — nieskończone oscylacje, 0.1–0.5 — zauważalne tłumione oscylacje (efekt odbicia), 1 — tłumienie krytyczne (bez oscylacji, płynne hamowanie).

ParametrZakresEfektPrzykład użycia
Stiffness100–1000Prędkość powrotu do równowagi200 = lista, 600 = przycisk
Damping0.0–1.0Tłumienie oscylacji0.3 = odbicie, 1.0 = bez oscylacji
Mass0.1–10.0Bezwładność obiektu1.0 = standard, 3.0 = ciężki element
Initial VelocityDowolnyPrędkość początkowa w pikselach/sPrędkość palca przy drag-to-dismiss

Tłumienie krytyczne (damping = 1.0) — optymalny tryb dla większości animacji UI: obiekt wraca do pozycji docelowej maksymalnie szybko bez przeregulowania. Dla efektu odbicia (np. pull-to-refresh) użyj damping = 0.3–0.5. Dla pojawiania się okien modalnych — damping = 0.6–0.8 z stiffness = 300–500. Masa rzadko jest zmieniana — standardowa wartość 1.0 pasuje do prawie wszystkich przypadków.

Spring Animation w iOS (Swift)

W iOS Spring Animation jest dostępna przez UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) od iOS 7 i CASpringAnimation (Core Animation) od iOS 9. Wersja UIView jest prostsza i popularniejsza do animacji właściwości View (transform, alpha, center). CASpringAnimation jest dokładniejsza i zapewnia dostęp do stiffness, damping i mass jako osobnych właściwości.

swift
import UIKit

// UIView.animate z parametrami sprężynowymi
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 — precyzyjna kontrola parametrów
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 — obliczony czas trwania
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")

CASpringAnimation.settlingDuration — unikalna właściwość Core Animation, która oblicza minimalny czas trwania animacji potrzebny sprężynie do osiągnięcia równowagi. Oznacza to, że nie musisz ręcznie dobierać duration — system sam określa, ile czasu zajmie tłumienie oscylacji. Dla UIView.animate czas trwania jest podawany jawnie, a damping 0.3–0.7 daje zauważalny efekt odbicia. Do współpracy z UIPanGestureRecognizer przekazuj velocityRecognizer.velocity(in: view) jako initialSpringVelocity — w ten sposób animacja kontynuuje ruch palca z tą samą prędkością.

Spring Animation w Android (Kotlin)

W Android SpringAnimation wchodzi w skład biblioteki AndroidX Dynamic Animation (androidx.dynamicanimation). Główna klasa — SpringAnimation, która animuje dowolną właściwość float View lub obiektu niestandardowego. Parametry ustawia się przez SpringForce — stiffness (domyślnie STIFFNESS_MEDIUM = 600) i dampingRatio (domyślnie DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).

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

// Kotlin: SpringAnimation z niestandardowym SpringForce
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 z prędkością początkową od gestu
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) "> Powrót do pozycji początkowej
                setStartVelocity(velocity)
                start()
            }
            true
        }
        else -> false
    }
}

"> SpringAnimation dla niestandardowej właściwości
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() }

Stałe 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). Dla RecyclerView z animacją elementów użyj SpringAnimation z DynamicAnimation.OnAnimationEndListener do zwalniania zasobów. Do animacji wielu właściwości użyj SpringAnimation.createFor(view, property).

Jetpack Compose: od Compose 1.0, animacja sprężynowa jest dostępna przez Animatable z spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). Jest to preferowany sposób dla projektów Compose, ponieważ SpringAnimation z DynamicAnimation jest kompatybilny tylko z systemem View. Wersja Compose spring używa tego samego silnika fizycznego, ale działa w kontekście Compose Animation System, automatycznie wstrzymując się przy detachment.

Spring Animation vs Easing: kiedy co wybrać

Spring Animation i krzywe Easing (easeInOut, FastOutSlowIn, decelerate) rozwiązują różne zadania. Krzywe Easing — to matematycznie zadana trajektoria z ustalonym czasem. Spring — symulacja fizyczna, gdzie czas zależy od parametrów i warunków początkowych. Do prostych animacji pojawiania/znikania krzywe Easing są wystarczające. Do animacji związanych z ruchem użytkownika (drag, swipe, scroll), Spring Animation daje bardziej naturalny feedback.

ScenariuszZalecenieParametry
Pojawienie elementuSpring (damping = 0.7, stiffness = 400)Płynne pojawienie z lekkim przeregulowaniem
Swipe-to-dismissSpring + prędkość początkowasetStartVelocity(velocity), damping = 0.5
Animacja ikonySpring (damping = 0.3, stiffness = 600)Wyraźne odbicie dla efektów akcentowych
Scroll physicsSpring (systemowa)Nie modyfikować — Android zarządza sam
Zmiana rozmiaruEasing (FastOutSlowIn)Easing jest bezpieczniejszy dla zmian layoutu

Anti-patterns: nie używaj Spring Animation do animacji parametrów layoutu (szerokość/wysokość View przez LayoutParams) — powoduje to przeliczanie hierarchii w każdej klatce, prowadząc do drgań i spadku FPS. Do animacji koloru również lepsze są krzywe Easing. Do animacji scroll position używaj systemowego Scroller z fling — Spring Animation nie daje tu przewagi. Dla maksymalnej wydajności na Android ogranicz liczbę jednocześnie aktywnych SpringAnimation do 10–15.

Często zadawane pytania

Jaka jest różnica między damping a stiffness?

Stiffness — sztywność sprężyny (siła powrotu). Wysoka wartość (1000) — szybki, gwałtowny ruch. Niska (100) — miękki, powolny. Damping — tłumienie (opór). Niskie (0.2) — długie oscylacje z odbiciem. Wysokie (1.0) — bez oscylacji, płynne hamowanie. Stiffness określa prędkość, damping — obecność i intensywność oscylacji.

Jak dobrać prawidłowe parametry Spring Animation?

Zacznij od damping = 0.5 i stiffness = 400 — to uniwersalny zestaw startowy dla iOS i Android. Do pojawiania elementów zwiększ damping do 0.7. Do efektów akcentowych (lajk, dodanie do koszyka) zmniejsz damping do 0.3 z stiffness = 600. Do Material Motion użyj damping = 0.6 i stiffness = 300. Sprawdzaj animację na rzeczywistym urządzeniu, a nie w symulatorze.

Czy Spring Animation działa w SwiftUI?

Tak, w SwiftUI animacja sprężynowa jest ustawiana przez .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) lub .spring(blendDuration: 0.3) w withAnimation. response i dampingFraction odpowiadają stiffness i damping z UIKit. Dla interactiveSpring() użyj .interactiveSpring() — specjalna wersja z prędkością początkową od gestu, zoptymalizowana do animacji drag.

Dlaczego Spring Animation na Android nie zatrzymuje się?

Sprawdź SpringForce.finalPosition — jeśli nie jest ustawiony lub jest równy bieżącej wartości, animacja może się nie rozpocząć. Wywołuj springAnim.cancel() w onPause() Activity/Fragment. Dla SpringAnimation w RecyclerView użyj view.setOnDetachListener { animator.cancel() }. Dla Jetpack Compose SpringAnimation automatycznie wstrzymuje się przy kompozycji.

Czy można płynnie przerwać Spring Animation?

Tak. W iOS wywołaj view.layer.removeAnimation(forKey:) — animacja zatrzyma się na bieżącej klatce. W Android wywołaj springAnim.cancel() — obiekt pozostanie na bieżącej pozycji. Dla płynnego przejścia do nowej wartości docelowej zaktualizuj finalPosition i nie wywołuj cancel — SpringAnimation automatycznie przeliczy trajektorię. Dla SkipToEnd użyj springAnim.skipToEnd() na Android.

Podsumowanie

  • Spring Animation — animacja oparta na fizycznym modelu sprężyny z parametrami stiffness i damping.
  • Damping — współczynnik tłumienia (0 = nieskończone oscylacje, 1 = tłumienie krytyczne).
  • Stiffness — sztywność sprężyny: 200 (soft), 600 (medium), 1800 (high) w Android.
  • iOS: UIView.animate z usingSpringWithDamping (UIKit) lub CASpringAnimation (Core Animation).
  • Android: SpringAnimation + SpringForce z AndroidX Dynamic Animation.
  • Jetpack Compose: animationSpec = spring(dampingRatio, stiffness) przez Animatable.
  • Spring Animation jest preferowana nad Easing dla animacji z gestami (swipe, drag, pull-to-refresh).

Opracujemy aplikację mobilną pod klucz

IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.

Omów projekt

Przeczytaj również