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 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също