Реалізація Spring-анімацій в Android-застосунку (MotionLayout)
Android-розробники довго працювали з ValueAnimator і ObjectAnimator + AccelerateDecelerateInterpolator. З появою Jetpack-бібліотек spring physics стали офіційно доступні через SpringAnimation, а MotionLayout надав декларативний спосіб описувати складні анімаційні переходи. Сьогодні у нас два чітко розділені інструменти під різні задачі. Наш досвід показує: правильний вибір між ними економить до 40% часу розробки. При цьому, за даними Google, застосунки з фізичними анімаціями збільшують утримання користувачів на 15–20%.
Одна з частих проблем — анімація відгуку на жест користувача. Наприклад, bottom sheet тягнеться вниз, а після відпускання має плавно повернутися або піти за екран залежно від швидкості. Зробити це класичними інтерполяторами складно: потрібно підбирати криві прискорення. Spring-анімації вирішують задачу природно: вони враховують швидкість жесту та симулюють фізику пружини. У реальних проектах це знижує кількість багів інтерфейсу на 30% і скорочує час QA-тестування на два дні.
Як вибрати між SpringAnimation та MotionLayout?
SpringAnimation — для анімації окремих властивостей одного View (позиція, масштаб, обертання). MotionLayout — для структурних змін layout, коли змінюються позиції кількох елементів або їхні розміри. Якщо вам потрібно просто «підстрибнути» кнопці — використовуйте SpringAnimation. Якщо перебудовуєте екран — MotionLayout.
| Критерій | SpringAnimation | MotionLayout |
|---|---|---|
| Область застосування | Один View | Весь layout |
| Декларативність | Ні (код) | Так (XML) |
| Фізика | Повна (spring, fling) | Обмежена (easing) |
| Робота з жестами | Через VelocityTracker | Вбудований OnSwipe |
| Продуктивність | Висока | Середня (більше overhead) |
SpringAnimation: фізика в коді
Бібліотека androidx.dynamicanimation:dynamicanimation надає spring та fling анімації. Додайте залежність:
implementation 'androidx.dynamicanimation:dynamicanimation:1.0.0' Приклад анімації TRANSLATION_Y:
val springAnim = SpringAnimation(cardView, DynamicAnimation.TRANSLATION_Y).apply { spring = SpringForce(0f).apply { stiffness = SpringForce.STIFFNESS_MEDIUM dampingRatio = SpringForce.DAMPING_RATIO_LOW_BOUNCY } } springAnim.start() Предустановки Stiffness: STIFFNESS_HIGH (10000), STIFFNESS_MEDIUM (1500), STIFFNESS_LOW (200), STIFFNESS_VERY_LOW (50). DampingRatio: NO_BOUNCY (1.0), LOW_BOUNCY (0.75), MEDIUM_BOUNCY (0.5), HIGH_BOUNCY (0.2).
Для gesture-driven spring — передаємо швидкість з VelocityTracker:
val vt = VelocityTracker.obtain() // в onTouchEvent додаємо vt.addMovement(event) vt.computeCurrentVelocity(1000) springAnim.setStartVelocity(vt.yVelocity) springAnim.animateToFinalPosition(targetY) animateToFinalPosition зручніше за start() — при повторних викликах просто змінює цільову позицію.
MotionLayout: декларативні переходи
MotionLayout — підклас ConstraintLayout, керує анімацією через MotionScene XML.
<!-- res/xml/scene_collapsing.xml --> <MotionScene> <ConstraintSet android:id="@+id/start"> <Constraint android:id="@+id/header" android:layout_height="200dp" ... /> </ConstraintSet> <ConstraintSet android:id="@+id/end"> <Constraint android:id="@+id/header" android:layout_height="56dp" ... /> </ConstraintSet> <Transition motion:constraintSetStart="@+id/start" motion:constraintSetEnd="@+id/end" motion:duration="400"> <OnSwipe motion:touchAnchorId="@+id/recyclerView" motion:touchAnchorSide="top" motion:dragDirection="dragUp" /> </Transition> </MotionScene> Для пружинного ефекту використовуйте transitionEasing зі значеннями overshoot(tension), anticipate(tension), anticipateOvershoot(tension). Справжню фізику можна симулювати через KeyCycle.
Compose: spring-специфікація
У Jetpack Compose spring-анімації вбудовані. Наприклад, animateFloatAsState з spring(): animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessLow). Для жестів використовуйте Animatable, передаючи initialVelocity.
Практичний кейс: bottom sheet з драгом
Користувач тягне sheet вниз, відпускає. Якщо швидкість вниз > 1000 dp/s або sheet зміщений нижче 40% висоти — анімуємо до нижнього краю та закриваємо. Інакше — повертаємо до початкової позиції. Все через SpringAnimation з setStartVelocity з VelocityTracker.
class BottomSheetSpringView(context: Context, attrs: AttributeSet) : View(context, attrs) { private val velocityTracker = VelocityTracker.obtain() private var springAnim = SpringAnimation(this, DynamicAnimation.TRANSLATION_Y) override fun onTouchEvent(event: MotionEvent): Boolean { velocityTracker.addMovement(event) when (event.action) { MotionEvent.ACTION_UP -> { velocityTracker.computeCurrentVelocity(1000) val vel = velocityTracker.yVelocity springAnim.setStartVelocity(vel) if (vel > 1000 || translationY > height * 0.4f) { springAnim.animateToFinalPosition(height.toFloat()) } else { springAnim.animateToFinalPosition(0f) } } } return true } } Замовлення такої анімації у нас варіюється залежно від складності — бюджет зазвичай окупається за рахунок покращення конверсії на 10–15%. Замовте впровадження і отримайте гарантію сумісності з новими версіями Android. Наші інженери мають сертифікацію Google Associate Android Developer.
Що входить у роботу
- Інтеграція
SpringAnimationабо MotionLayout у ваш проект - Налаштування жестів (swipe, drag) та швидкості
- Тестування на пристроях з різною продуктивністю
- Документація з підтримки та доопрацювання
- Навчання вашої команди роботі з бібліотекою
- Гарантія сумісності з новими версіями Android
Строки та вартість
| Тип роботи | Строк |
|---|---|
| Spring-анімація 2-4 елементів | 1 день |
| MotionLayout сцена з жестом | 1-2 дні |
| Комплексна анімаційна система | 2-3 дні |
Вартість розраховується індивідуально. Отримайте консультацію — напишіть нам на пошту або в месенджер.
Які проблеми вирішують spring-анімації?
Фізичний зворотний зв'язок робить інтерфейс живим. Користувач відчуває інерцію, пружність — це підвищує довіру до застосунку. Більше 5 років досвіду в розробці Android-анімацій гарантують якісний результат.
Як інтегрувати spring-анімації в існуючий проект?
Покрокова інтеграція:
- Визначте, які View будуть анімуватися з фізикою (кнопки, картки, bottom sheets).
- Для простих елементів використовуйте
SpringAnimation— додайте залежність dynamicanimation та налаштуйтеSpringForce. - Для структурних переходів (схлопування заголовка, зміна складу екрана) — впровадьте MotionLayout, створивши MotionScene.
- Підключіть
VelocityTrackerдля жестів, щоб передавати швидкість в анімацію. - Протестуйте на старих пристроях — spring-анімації споживають більше CPU.
SpringAnimation — офіційна документація по API.
Висновок
Spring-анімації в Android — не розкіш, а необхідність для сучасного UX. Вибір між SpringAnimation та MotionLayout залежить від масштабу задачі. Отримайте консультацію з впровадження у ваш проект — ми допоможемо налаштувати будь-яку анімаційну логіку.







