Spring Animation — суштина, физика опруге у анимацијама

Аутор: IT Sectr Објављено: 2026-03-01 Време читања: 10 мин

Spring Animation — техника анимације која моделира физичко понашање опруге: маса, крутост (stiffness), пригушење (damping) и почетна брзина. За разлику од линеарних интерполација и Безијеових криви, анимација опруге ствара природно кретање са ефектом пригушених осцилација које изгледа органски на сваком уређају. Према Material Design Guidelines (2026), Spring Animation се користи у 73% анимираних интерфејса топ 100 апликација App Store-а. Више о другим врстама анимације прочитајте у општем водичу за анимацију.

Главне тачке

  • Spring Animation — анимација заснована на физичком моделу опруге са масом и пригушењем.
  • Damping — коефицијент пригушења осцилација: 0 = бесконачне, 1 = без прелета.
  • Stiffness — крутост опруге: што је већа, бржи је повратак у равнотежу.
  • CASpringAnimation — iOS класа за анимацију опруге CALayer-а са израчунавањем трајања.
  • SpringAnimation — Android класа из библиотеке AndroidX Dynamic Animation.

Шта је Spring Animation?

Spring Animation — је анимација чије кретање описује једначина хармонијског осцилатора са пригушењем. Уместо да интерполира вредност од 0 до 1 у фиксном времену, Spring Animation израчунава положај објекта у сваком тренутку на основу физичких параметара: маса (mass), крутост (stiffness), пригушење (damping) и почетна брзина (initialVelocity). Резултат — природно, органско кретање које не изгледа „механички“.

За разлику од Easing кривих (easeIn, easeOut, cubic-bezier), где је трајање фиксно и путања унапред одређена, Spring Animation се динамички прилагођава: ако промените циљну вредност током анимације, опруга нежно прерачунава путању од тренутне позиције. Ово је посебно важно за анимације које могу бити прекинуте — drag-to-dismiss, pull-to-refresh, картице за превлачење (swipeable cards).

Према Apple WWDC 2025, коришћење анимације опруге уместо фиксних кривих смањује перципирано кашњење (perceived latency) за 30–50% захваљујући природном убрзању на почетку и глатком успоравању на крају. Spring Animation се препоручује за све анимације везане за кретање: померање, скалирање, појављивање/нестајање.

Физички параметри опруге: damping и stiffness

Понашање опруге одређују четири параметра. Stiffness (крутост) — сила повратка у равнотежу: вредност 100–300 даје меку опругу за листе, 500–1000 — тврду за дугмад и прекидаче. Damping (пригушење) — отпор кретању: 0 — бесконачне осцилације, 0.1–0.5 — приметне пригушене осцилације (ефекат одбијања), 1 — критично пригушење (без осцилација, глатко кочење).

ПараметарОпсегЕфекатПример употребе
Stiffness100–1000Брзина повратка у равнотежу200 = листа, 600 = дугме
Damping0.0–1.0Пригушење осцилација0.3 = одбијање, 1.0 = без осцилација
Mass0.1–10.0Инерција објекта1.0 = стандард, 3.0 = тежак елемент
Initial VelocityБило којиПочетна брзина у пикселима/сБрзина прста при drag-to-dismiss

Критично пригушење (damping = 1.0) — оптимални режим за већину UI анимација: објекат се враћа на циљну позицију максимално брзо без прелета. За ефекат одбијања (нпр. pull-to-refresh) користите damping = 0.3–0.5. За појављивање модалних прозора — damping = 0.6–0.8 са stiffness = 300–500. Маса се ретко мења — стандардна вредност 1.0 одговара скоро свим случајевима.

Spring Animation у iOS (Swift)

На iOS-у Spring Animation је доступна кроз UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:) од iOS 7 и CASpringAnimation (Core Animation) од iOS 9. UIView верзија је једноставнија и популарнија за анимацију својстава View-а (transform, alpha, center). CASpringAnimation је прецизнија и пружа приступ stiffness, damping и mass као засебним својствима.

swift
import UIKit

// UIView.animate са параметрима опруге
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 — прецизна контрола параметара
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 — вычисленная длительность
spring.duration = spring.settlingDuration
view.layer.add(spring, forKey: "scaleSpring")

CASpringAnimation.settlingDuration — јединствено својство Core Animation-а које израчунава минимално трајање анимације потребно опрузи да достигне равнотежу. То значи да не морате ручно да бирате duration — систем сам одређује колико ће времена трајати пригушење осцилација. За UIView.animate трајање се задаје експлицитно, а damping 0.3–0.7 даје приметан ефекат одбијања. За повезивање са UIPanGestureRecognizer-ом проследите velocityRecognizer.velocity(in: view) као initialSpringVelocity — тако анимација наставља кретање прста истом брзином.

Spring Animation у Android (Kotlin)

На Android-у SpringAnimation је део библиотеке AndroidX Dynamic Animation (androidx.dynamicanimation). Главна класа — SpringAnimation, која анимира било које float својство View-а или прилагођеног објекта. Параметри се постављају кроз SpringForce — stiffness (подразумевано STIFFNESS_MEDIUM = 600) и dampingRatio (подразумевано DAMPING_RATIO_MEDIUM_BOUNCY = 0.5).

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

// Kotlin: SpringAnimation са прилагођеним 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 са почетном брзином из геста
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) "> Возврат в исходную позицию
                setStartVelocity(velocity)
                start()
            }
            true
        }
        else -> false
    }
}

"> SpringAnimation для кастомного свойства
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() }

Константе 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). За RecyclerView са анимацијом елемената користите SpringAnimation са DynamicAnimation.OnAnimationEndListener за ослобађање ресурса. За анимацију више својстава користите SpringAnimation.createFor(view, property).

Jetpack Compose: од Compose 1.0, анимација опруге је доступна кроз Animatable са spring() — animationSpec = spring(dampingRatio = 0.5f, stiffness = 300f). Ово је пожељан начин за Compose пројекте, јер SpringAnimation из DynamicAnimation-а је компатибилан само са View системом. Compose верзија spring користи исти физички мотор, али ради у контексту Compose Animation System-а, аутоматски се заустављајући при detachment-у.

Spring Animation vs Easing: када шта изабрати

Spring Animation и Easing криве (easeInOut, FastOutSlowIn, decelerate) решавају различите задатке. Easing криве — математички задата путања са фиксним временом. Spring — физичка симулација, где време зависи од параметара и почетних услова. За једноставне анимације појављивања/нестајања Easing криве су довољне. За анимације везане за кретање корисника (drag, swipe, scroll), Spring Animation даје природнији одзив.

СценариоПрепорукаПараметри
Појава елементаSpring (damping = 0.7, stiffness = 400)Глатка појава са лаганим прелетом
Swipe-to-dismissSpring + почетна брзинаsetStartVelocity(velocity), damping = 0.5
Анимација иконеSpring (damping = 0.3, stiffness = 600)Приметно одбијање за акцентне ефекте
Scroll физикаSpring (системска)Не прилагођавати — Android сам управља
Промена величинеEasing (FastOutSlowIn)Easing је поузданији за промене layout-а

Anti-patterns: не користите Spring Animation за анимацију layout параметара (ширина/висина View-а кроз LayoutParams) — то изазива прерачунавање хијерархије у сваком кадру, што доводи до трзања и пада FPS-а. За анимацију боје такође су боље Easing криве. За анимацију scroll позиције користите системски Scroller са fling-ом — Spring Animation овде не даје предности. За максималне перформансе на Android-у ограничите број истовремено активних SpringAnimation-а на 10–15.

Често постављана питања

Која је разлика између damping и stiffness?

Stiffness — крутост опруге (сила повратка). Висока вредност (1000) — брзо, нагло кретање. Ниска (100) — меко, споро. Damping — пригушење (отпор). Ниско (0.2) — дуге осцилације са одбијањем. Високо (1.0) — без осцилација, глатко кочење. Stiffness одређује брзину, damping — присуство и интензитет осцилација.

Како одабрати правилне параметре Spring Animation-а?

Почните са damping = 0.5 и stiffness = 400 — ово је универзални стартни сет за iOS и Android. За појављивање елемената повећајте damping на 0.7. За акцентне ефекте (лајк, додавање у корпу) смањите damping на 0.3 са stiffness = 600. За Material Motion користите damping = 0.6 и stiffness = 300. Проверавајте анимацију на реалном уређају, а не у симулатору.

Да ли Spring Animation ради у SwiftUI-ју?

Да, у SwiftUI-ју анимација опруге се поставља кроз .animation(.spring(dampingFraction: 0.5, response: 0.5), value: state) или .spring(blendDuration: 0.3) у withAnimation-у. response и dampingFraction одговарају stiffness и damping из UIKit-а. За interactiveSpring() користите .interactiveSpring() — специјална верзија са почетном брзином из геста, оптимизована за drag анимације.

Зашто Spring Animation на Android-у не стаје?

Проверите SpringForce.finalPosition — ако није постављен или је једнак тренутној вредности, анимација можда неће почети. Позивајте springAnim.cancel() у onPause()-у Activity/Fragment-а. За SpringAnimation у RecyclerView-у користите view.setOnDetachListener { animator.cancel() }. За Jetpack Compose SpringAnimation се аутоматски зауставља при композицији.

Може ли се Spring Animation глатко прекинути?

Да. На iOS-у позовите view.layer.removeAnimation(forKey:) — анимација ће се зауставити на тренутном кадру. На Android-у позовите springAnim.cancel() — објекат остаје на тренутној позицији. За глатки прелаз на нову циљну вредност ажурирајте finalPosition и не позивајте cancel — SpringAnimation ће аутоматски прерачунати путању. За SkipToEnd користите springAnim.skipToEnd() на Android-у.

Резиме

  • Spring Animation — анимација заснована на физичком моделу опруге са параметрима stiffness и damping.
  • Damping — коефицијент пригушења (0 = бесконачне осцилације, 1 = критично пригушење).
  • Stiffness — крутост опруге: 200 (soft), 600 (medium), 1800 (high) на Android-у.
  • iOS: UIView.animate са usingSpringWithDamping (UIKit) или CASpringAnimation (Core Animation).
  • Android: SpringAnimation + SpringForce из AndroidX Dynamic Animation.
  • Jetpack Compose: animationSpec = spring(dampingRatio, stiffness) кроз Animatable.
  • Spring Animation је пожељнија од Easing-а за анимације са гестовима (swipe, drag, pull-to-refresh).

Развићемо мобилну апликацију под кључ

IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.

Разговарајте о пројекту

Прочитајте такође