Реалізація жестових анімацій (Interactive Gesture Animations) у мобільних додатках
Різниця між жестовою анімацією та звичайною в тому, що вона переривається. Користувач тягне карточку, передумує на середине, й вона повинна повернутися обратно з фізично достовірною поведінкою — не просто прискочити в вихідну позицію, а «отпружинити» з урахуванням накопленої швидкості. Це і є interactive gesture animation — анімація, керована пальцем у реальному часі.
Фізика — основа правильного відчуття
Ключевий параметр будь-якої жестової анімації — зв'язок між швидкістю жеста при відпусканні (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 — кінець. Користувач буквально «тягне» анімацію за собою.
Свайп для вислизання карточки
Класичний паттерн у стилі 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 — це саме та синхронізація, про яку говоримо.
Pull-to-Refresh з кастомною анімацією
Стандартний UIRefreshControl та SwipeRefreshLayout не підтримують кастомну анімацію — реалізуємо через ScrollView з негативним offset: коли contentOffset.y < -threshold, включаємо кастомний індикатор з параметром прогресу = abs(offset.y) / threshold. Lottie-анімація, привʼязана до setProgress(), дає довільний дизайн.
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 на 60Hz-пристроях.
Терміни реалізації: 2–3 дні на один паттерн жестової анімації, включаючи інтеграцію та калібровку під конкретний дизайн.







