Реалізація Spring-анімацій (фізичних) в iOS-застосунку

TRUETECH займається розробкою, підтримкою та обслуговуванням мобільних додатків iOS, Android, PWA. Маємо великий досвід та експертизу для публікації мобільних додатків до популярних маркетів Google Play, App Store, Amazon, AppGallery та інші.

Розробка та підтримка будь-яких видів мобільних додатків:

Інформаційні та розважальні мобільні програми
Новинки, ігри, довідники, онлайн-каталоги, погодні, фітнес та здоров'я, туристичні, освітні, соціальні мережі та месенджери, квіз, блоги та подкасти, форуми, агрегатори
Мобільні програми електронної комерції
Інтернет-магазини, B2B-додатки, маркетплейси, онлайн-обмінники, кешбек-сервіси, біржі, дропшиппінг-платформи, програми лояльності, доставка їжі та товарів, платіжні системи
Мобільні програми для управління бізнес-процесами
CRM-системи, ERP-системи, управління проектами, інструменти для команди продажів, облік фінансів, управління виробництвом, логістика та доставка, управління персоналом, системи моніторингу даних
Мобільні програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, платформи надання електронних послуг, платформи кешбеку, відеохостинги, тематичні портали, платформи онлайн-бронювання та запису, платформи онлайн-торгівлі

Це лише деякі з типів мобільних додатків, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1735 послуг
Реалізація Spring-анімацій (фізичних) в iOS-застосунку
Середній
від 1 дня до 3 днів
Часті запитання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    495

Впровадження Spring-анімацій (фізичних) в iOS-додатки

Spring-анімації роблять інтерфейс живим—елементи не просто рухаються, вони «пружинять», дещо перелітаючи цільову точку й повертаючись назад. iOS використовує їх скрізь: іконки при довгому натиску, карточки в App Store, клавіші клавіатури. Різниця між «зробленим як у системі» та «майже як у системі» — у правильних параметрах фізичної моделі.

UIKit: UISpringTimingParameters та UIViewPropertyAnimator

До iOS 10 spring-анімації робили через UIView.animate(withDuration:delay:usingSpringWithDamping:initialSpringVelocity:). Параметри dampingRatio (0–1) та initialVelocity працюють, але це спрощена модель—не справжня фізика пружини.

З iOS 10 — UISpringTimingParameters з mass, stiffness та damping:

let timingParams = UISpringTimingParameters(
    mass: 1.0,
    stiffness: 170,
    damping: 26,
    initialVelocity: CGVector(dx: 0, dy: 0)
)
let animator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParams)
animator.addAnimations {
    self.cardView.transform = CGAffineTransform(scaleX: 0.95, y: 0.95)
}
animator.startAnimation()

duration: 0 — при використанні spring timing duration ігнорується, анімація триває стільки, скільки потрібно пружині для затухання. Це правильно—не встановлюйте duration для spring.

Параметри для типових випадків: stiffness: 300, damping: 30 — швидка пружна анімація (зворотний зв'язок при натиску). stiffness: 120, damping: 14 — повільна м'яка пружина (появлення bottom sheet). stiffness: 400, damping: 40 — жорстка без перельоту (переключатель).

UIViewPropertyAnimator підтримує isInterruptible = true — вимкніть та перенаправте анімацію під час. Це критично для gesture-driven UI: якщо користувач почав тягти карточку вниз й передумав—анімація плавно реверсується з поточною швидкістю.

SwiftUI: spring() та .interpolatingSpring()

SwiftUI пропонує кілька варіантів:

// Простий spring з dampingFraction
withAnimation(.spring(response: 0.4, dampingFraction: 0.7)) {
    isExpanded.toggle()
}

// Фізична модель через interpolatingSpring
withAnimation(.interpolatingSpring(stiffness: 170, damping: 26)) {
    offset = targetOffset
}

// iOS 17+: новий Spring тип
withAnimation(.spring(.bouncy(duration: 0.4, extraBounce: 0.1))) {
    scale = 1.0
}

.spring(response:dampingFraction:) — простіше у використанні: response — це приблизна тривалість (не жорстка), dampingFraction 1.0 — критичне затухання без перельоту, менше 1.0 — перельот. Для більшості UI: response: 0.3–0.5, dampingFraction: 0.7–0.85.

iOS 17 принесла іменовані spring presets: .bouncy, .smooth, .snappy — корисні для швидкого прототипування, але для фінального продукту краще явно встановлювати параметри.

Matching швидкості при переривання: коли жест переривує анімацію, нова spring повинна почватися з поточної швидкості. У SwiftUI використовуйте @GestureState та withAnimation з правильним initialVelocity. У UIKit — використовуйте UIViewPropertyAnimator.fractionComplete та continueAnimation(withTimingParameters:durationFactor:).

Gesture-Driven Spring: UIPanGestureRecognizer + Spring

Найживіший кейс—карточка, яку можна тягти, і вона пружинить назад чи летить на наступну позицію:

@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
    let translation = gesture.translation(in: view)

    switch gesture.state {
    case .changed:
        cardView.transform = CGAffineTransform(translationX: 0, y: translation.y)
    case .ended:
        let velocity = gesture.velocity(in: view)
        let velocityVector = CGVector(dx: 0, dy: velocity.y / 1000) // нормалізація

        let timingParams = UISpringTimingParameters(
            mass: 1, stiffness: 200, damping: 28,
            initialVelocity: velocityVector
        )
        let animator = UIViewPropertyAnimator(duration: 0, timingParameters: timingParams)
        animator.addAnimations {
            self.cardView.transform = .identity
        }
        animator.startAnimation()
    default: break
    }
}

Беріть initialVelocity з швидкості жесту, нормалізуйте діленням на ~1000 (шкала UISpringTimingParameters відрізняється від points/second швидкості жесту).

Час розробки

Додавання spring-анімацій до існуючих UI-компонентів (2–4 елементи) займає 1–2 дні з тестуванням на пристроях. Gesture-driven інтерактивний екран з spring physics займає 2–3 дні. Вартість розраховується індивідуально.