Реалізація жестових анімацій (Interactive Gesture Animations) у мобільному додатку
Ми створюємо жестові анімації, які не гальмують і не виглядають дешево. Наш досвід — понад 5 років у мобільній розробці, більше 20 проєктів з кастомними анімаціями. Різниця між жестовою анімацією та звичайною в тому, що вона переривана. Користувач тягне картку, передумує на середині, і вона має повернутися назад з фізично достовірною поведінкою — не просто стрибнути у вихідне положення, а «відпружинити» з урахуванням накопиченої швидкості. Це і є інтерактивна жестова анімація — анімація, керована пальцем у реальному часі.
Чому синхронізація швидкості — головний виклик?
Ключовий параметр будь-якої жестової анімації — зв'язок між швидкістю жесту в момент відпускання (gestureRecognizer.velocity) і параметрами анімації завершення. Якщо їх не синхронізувати, виходить «стрибок»: палець рухається з однією швидкістю, а об'єкт закінчує рух з іншою.
На iOS UIViewPropertyAnimator вирішує це нативно через continueAnimation(withTimingParameters:durationFactor:):
@objc func handlePan(_ gesture: UIPanGestureRecognizer) {
let translation = gesture.translation(in: view)
switch gesture.state {
case .changed:
animator?.fractionComplete = translation.y / totalDistance
case .ended:
let velocity = gesture.velocity(in: view)
let springVelocity = abs(velocity.y) / (totalDistance - translation.y)
let timing = UISpringTimingParameters(dampingRatio: 0.8,
initialVelocity: CGVector(dx: 0, dy: springVelocity))
animator?.continueAnimation(withTimingParameters: timing, durationFactor: 0)
default: break
}
}
fractionComplete — це пряме керування прогресом анімації жестом. Значення 0.0 — початок, 1.0 — кінець. Користувач буквально «тягне» анімацію за собою. Для глибокого розуміння рекомендую офіційну документацію UIKit.
Як реалізувати свайп для відхилення картки?
Класичний патерн у стилі Tinder або списків завдань: картка слідує за пальцем, при досягненні порогу — відлітає, при недостатньому зміщенні — повертається.
Три параметри, які потрібно відкалібрувати:
- Поріг відпускання — зазвичай 30-40% ширини екрану або швидкість > 800 pt/s
- Кут обертання —
transform = CGAffineTransform(rotationAngle: translation.x / screenWidth * 0.3)— створює відчуття фізики - Швидкість анімації відльоту — має відповідати швидкості жесту, інакше картка «гальмує» в повітрі
На Android реалізуємо через ViewDragHelper або ItemTouchHelper (для RecyclerView). ItemTouchHelper хороший для списків, але обмежений: кастомний feedback малюнок вимагає перевизначення onChildDraw. У Flutter — Dismissible для простих випадків, GestureDetector + AnimationController з fling() для складних. fling() приймає velocity безпосередньо з DragEndDetails.velocity.pixelsPerSecond — це саме та синхронізація, про яку говоримо.
Порівняння підходів на різних платформах
| Параметр | iOS | Android | Flutter |
|---|---|---|---|
| Синхронізація velocity | UIViewPropertyAnimator.continueAnimation |
ViewDragHelper + VelocityTracker |
fling(velocity) |
| Свайп картки | fractionComplete + UISpringTimingParameters |
ItemTouchHelper + RecyclerView |
Dismissible + DragTarget |
| Pull-to-refresh кастом | ScrollView offset + Lottie | Custom SwipeRefreshLayout + Lottie |
RefreshIndicator + AnimationController |
Час відгуку: жестові vs звичайні анімації
| Тип анімації | Час відгуку на дотик | Переривання | Фізичність |
|---|---|---|---|
| Жестова | < 16 мс | Так | Висока |
| Звичайна | 100-200 мс | Ні | Низька |
Pull-to-refresh з кастомною анімацією
Стандартний UIRefreshControl і SwipeRefreshLayout не підтримують кастомну анімацію індикатора. Реалізуємо через ScrollView з від'ємним offset: коли contentOffset.y < -threshold, вмикаємо кастомний індикатор з параметром прогресу = abs(offset.y) / threshold. Lottie-анімація, прив'язана до setProgress(), дає довільний дизайн. Для Lottie-анімацій використовуємо LottieAnimationView.setProgress() на iOS та LottieDrawable.setProgress() на Android, що дозволяє точно прив'язати прогрес анімації до зміщення.
Drag & Drop з фізичною поведінкою
На iOS — UIDragInteraction + UIDropInteraction для cross-app DnD, UILongPressGestureRecognizer + UIViewPropertyAnimator для внутрішньоекранного. Важливо: при піднятті елемента додаємо scale-анімацію (1.05) і тінь — візуальний сигнал «я тримаю об'єкт». При поверненні — UISpringTimingParameters з високим dampingRatio (0.9) для ефекту «м'якої посадки».
Тестування та калібрування
- Налаштуйте Slow Animations в симуляторі для візуального налагодження.
- Запустіть Xcode Instruments — Animation Hitches на фізичному пристрої, досягніть GPU frame time не більше 16ms (60fps).
- Перевірте всі стани: утримання, швидкий свайп, повторний дотик під час анімації.
- Переконайтеся, що параметри анімації (damping, stiffness) узгоджені з дизайном.
Примітка
Для глибокого налагодження використовуйте Xcode Instruments та Profile GPU Rendering на Android.Жестові анімації обов'язково тестуємо на фізичному пристрої — емулятор не відтворює точну сенсорну фізику. Slow Animations в симуляторі допомагає виявити артефакти, але реальне відчуття — тільки на залізі. На Android використовуйте ViewPropertyAnimator та перевіряйте gpu frame time через Profile GPU Rendering. У релізній збірці переконайтеся, що ProGuard не вирізав класи Lottie: додайте -keep class com.airbnb.lottie.** { *; }.
Процес оцінки та роботи
- Збір даних — аналіз вимог та наявного дизайну.
- Аудит — оцінка складності та сумісності з платформою.
- Проектування — вибір підходу (UIKit, ViewDragHelper, Flutter).
- Оцінка — визначення термінів та орієнтовної вартості.
- Розробка — створення прототипу з калібруванням параметрів.
- Тестування — на 5+ фізичних пристроях, перевірка 60fps.
- Запуск — передача коду з коментарями, підтримка 2 тижні.
Орієнтири за термінами
Реалізація одного патерну жестової анімації займає від 2 до 3 днів, включаючи інтеграцію та калібрування під конкретний дизайн. Для складніших рішень (Lottie, Rive) термін може збільшитися до 5 днів.
Що входить у роботу
- Розробка прототипу анімації з калібруванням параметрів
- Інтеграція з вашим дизайном (Lottie, Rive або Core Animation)
- Тестування на 5+ фізичних пристроях
- Передача вихідного коду з коментарями
- Підтримка протягом 2 тижнів після релізу
Отримайте консультацію щодо вашого проєкту — зв'яжіться з нами для оцінки.







