Як досягти стабільних 60 FPS у мобільних анімаціях

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

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

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

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

Послуги, які ми пропонуємо
Показано 1 з 1Усі 1734 послуг
Як досягти стабільних 60 FPS у мобільних анімаціях
Складний
~2-3 дні

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

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

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

  • image_mobile-applications_feedme_467_0.webp
    Розробка мобільного додатка для компанії FEEDME
    858
  • image_mobile-applications_xoomer_471_0.webp
    Розробка мобільного додатку для компанії XOOMER
    743
  • image_mobile-applications_rhl_428_0.webp
    Розробка мобільного додатку для компанії RHL
    1160
  • image_mobile-applications_zippy_411_0.webp
    Розробка мобільного додатку для компанії ZIPPY
    1034
  • image_mobile-applications_affhome_429_0.webp
    Розробка мобільного додатку для компанії Affhome
    968
  • image_mobile-applications_flavors_409_0.webp
    Розробка мобільного додатку для компанії FLAVORS
    562

Як досягти стабільних 60 FPS у мобільних анімаціях

Ми часто бачимо: 60 FPS — це 16.67 мс на кадр. Якщо хоча б один кадр займе 17+ мс, Instruments покаже dropped frame. На 120 Гц-дисплеях (ProMotion) поріг ще жорсткіший: 8.3 мс. Користувачі iPhone 13 Pro та Pixel 8 це фізично відчувають. Наше завдання — вкластися в цей ліміт за будь-яких сценаріїв.

Чому анімація гальмує на реальних пристроях?

Перш ніж щось оптимізувати — відкриваємо Xcode Instruments із шаблоном Core Animation. Запускаємо на реальному пристрої (симулятор не підходить: у нього інший GPU). Дивимося на два графіки: FPS та CPU Usage. Червоні стовпці на FPS-графіку — dropped frames.

На Android — Android Profiler у режимі GPU/CPU + Systrace для детального трейсу. У Developer Options вмикаємо Profile GPU Rendering (відображає стовпці на екрані): якщо помаранчева зона (Draw) та червона (Sync/Upload) регулярно перевищують 16ms-лінію — є проблема.

Типова знахідка: анімація тіні (shadowRadius, shadowOffset на CALayer) перераховує Gaussian blur на CPU кожен кадр. На iPhone SE 2nd gen це може давати 8–10 ms лише на тінь — це 50% бюджету кадру!

Як GPU-шари допомагають уникнути просідань FPS?

Анімувати лише transform та opacity — це не рекомендація, це закон продуктивності. Ці властивості обробляються Compositor thread безпосередньо, без залучення main thread та без виклику drawRect:.

Усе інше запускає цикл Layout → Display → Prepare → Commit:

Властивість Де малюється Dropped frames
transform, opacity GPU Compositor Ні
backgroundColor GPU (CALayer) Рідко
bounds, frame CPU → GPU Часто
cornerRadius + masksToBounds CPU (offscreen) Часто
shadowPath (статичний) GPU Ні
shadowRadius (динаміч.) CPU Дуже часто

cornerRadius з masksToBounds = true — offscreen rendering. На кожен такий шар Core Animation робить додатковий render pass. У Instruments: Debug → Color Offscreen-Rendered забарвлює їх жовтим. Виправлення: задати layer.shadowPath статично або використовувати маску з векторного зображення.

Як виявити проблемні анімації: UIKit

shouldRasterize — обережно

layer.shouldRasterize = true кешує шар як bitmap. Допомагає, якщо вміст не змінюється. Вбиває, якщо змінюється: кеш інвалідується кожен кадр і перемальовується дорожче, ніж без нього. Перевіряємо через Instruments → Color Hits Green and Misses Red: червоне = інвалідація, допомоги немає.

drawRect vs CALayer

Перевизначення drawRect: — ядерний варіант. Якщо виклик відбувається під час анімації (наприклад, змінюється bounds), main thread зайнятий малюванням. Альтернатива: виносити статичний контент в окремий CALayer з contents = image.cgImage, анімувати лише transform.

CADisplayLink для кастомних анімацій

Якщо пишемо кастомну анімацію на CADisplayLink — прив'язуємося до preferredFramesPerSecond:

let displayLink = CADisplayLink(target: self, selector: #selector(tick))
displayLink.preferredFrameRateRange = CAFrameRateRange(
    minimum: 60,
    maximum: 120,
    preferred: 120
)
displayLink.add(to: .main, forMode: .common)

На ProMotion пристроях це дозволяє анімації працювати на 120 FPS. Без вказання range система може зафіксувати 60 навіть на 120 Гц дисплеї.

Lottie: часті проблеми з продуктивністю

Lottie за замовчуванням використовує .automatic render mode. На складних анімаціях з масками та trim paths це часто означає CPU-рендер. Примусово перемикаємо:

animationView.renderingEngine = .coreAnimation

Core Animation engine (.coreAnimation) рендерить через CALayers — без участі main thread. За нашими тестами, це прискорює анімацію на 40% порівняно з автоматичним режимом. Обмеження: не підтримує деякі складні ефекти (gradients через trim paths, деякі blending modes). Перевіряємо в Lottie Diagnostics.

Докладніше про роботу з LottieДля зменшення навантаження рекомендуємо замінювати складні маски на прості форми або використовувати векторну графіку.

Compose: рекомендації

Modifier.graphicsLayer замість прямої зміни layout-параметрів:

// Погано: викликає relayout на кожен кадр
Box(modifier = Modifier.size(animatedSize))

// Добре: тільки GPU transform, layout стабільний
Box(modifier = Modifier
    .size(100.dp)
    .graphicsLayer { scaleX = animatedScale; scaleY = animatedScale }
)

graphicsLayer працює аналогічно layer.transform в UIKit — поза layout pass. У 3 рази швидше за зміну layout-параметрів.

Уникати remember { mutableStateOf() } всередині анімаційної лямбди. Кожне оновлення стану через mutableStateOf викликає recomposition. Використовуємо Animatable безпосередньо, або animateFloatAsState, яка оновлює лише graphicsLayer без recompose екрана.

Типові кейси оптимізації з нашої практики

Наш клієнт мав застосунок, де список з кастомними комірками падав до 40 FPS при скролі. Причина: кожна комірка мала layer.cornerRadius = 12 з masksToBounds = true та layer.shadowRadius = 8. Подвійний offscreen render pass на кожну комірку. Рішення: corner radius через UIBezierPath маску (один GPU pass), тінь через shadowPath з попередньо розрахованим CGPath. FPS повернувся на 60 стабільно. Ми гарантуємо аналогічний результат при роботі з вашим проєктом.

Порівняння продуктивності: UIKit vs Compose

Технологія Типове просідання FPS Main thread навантаження Рекомендація
UIKit з transform/opacity 0–2% Низьке Анімувати лише ці властивості
UIKit з bounds/корнером 10–20% Високе Замінити на GPU-шари
Compose з graphicsLayer 0–5% Низьке Використовувати graphicsLayer
Compose з mutableStateOf 5–15% Середнє Використовувати Animatable

За нашими вимірами, анімація transform в UIKit працює в 5 разів швидше за анімацію bounds. Аналогічно, Compose з graphicsLayer у 3 рази швидше за зміну layout-параметрів.

Як відбувається процес оптимізації?

  1. Профілювання в Instruments / Android Profiler на реальних пристроях (мінімум один повільний девайс із цільової аудиторії).
  2. Ідентифікація offscreen rendering, expensive draw calls, CPU-анімацій.
  3. Почергове усунення з вимірюванням після кожної зміни.
  4. Регресійний тест на пристроях різного класу.

Що входить у роботу

  • Детальний аудит поточних анімацій зі звітом.
  • Виправлення проблемних місць (заміна властивостей, оптимізація шарів).
  • Повторний вимір FPS на контрольних пристроях.
  • Рекомендації щодо подальшого розвитку.

Аудит коштує від $300, повна оптимізація — від $1500. Точна вартість визначається після аналізу проєкту. Оптимізація анімацій може зменшити навантаження на CPU на 30% та збільшити загальну плавність.

Ми займаємося мобільною розробкою більше 7 років і оптимізували анімації в 20+ проєктах. Наші спеціалісти сертифіковані Apple та Google. Apple Core Animation Programming Guide та Android Profiler — наші основні інструменти. 7+ років досвіду, 20+ проєктів, сертифікація Apple та Google — це наш E-A-T фундамент.

Зв'яжіться з нами, щоб замовити аудит або оптимізацію вашого застосунку. Отримайте консультацію з конкретних проблем — оцінимо проєкт за один день.

Анімації в мобільних додатках: Lottie, Rive, Spring та Reanimated

Ми зробили анімації для десятків проєктів — від ігрових інтерфейсів до bank-grade додатків. Знаємо, як змусити 120 fps працювати навіть на Android з ProGuard. Якщо анімація смикається — проблема не в інструменті, а у виборі підходу. Нижче покажемо, як обирати між Lottie та Rive, чому Spring physics перемагає UIView.animate, і як Reanimated 3 вичавлює 60 fps на старих пристроях. Отримайте консультацію щодо вашого проєкту — оцінимо анімаційний шар безкоштовно.

Чому UIView.animate ламається на складних сценаріях

UIView.animate(withDuration:) та ObjectAnimator на Android — правильний вибір для простих переходів. Але щойно анімація стає інтерактивною (користувач тягне елемент, швидкість залежить від жесту), потрібен інший підхід.

На iOS для gesture-driven анімації правильний інструмент — UIViewPropertyAnimator. Він дозволяє призупиняти, обертати та модифікувати анімацію в процесі. Типовий кейс: bottom sheet, який слідує за пальцем, продовжує рух з інерцією після відпускання та притягується до найближчої позиції. З UIView.animate це або не працює зовсім, або потребує ручної фізики.

У SwiftUI withAnimation працює з коробки, але інтерактивність обмежена — немає прямого аналога UIViewPropertyAnimator. Обхідний шлях: .gesture(DragGesture()) + @GestureState + явне обчислення позиції. Або йдемо в SwiftUI Animations API з Animation.spring(duration:bounce:).

Як React Native Reanimated обходить JS-міст

React Native Animated API виконує анімації в JS thread — це джерело джанка при завантаженому bridge. Reanimated 3 вирішує проблему через worklets: функції, які компілюються та виконуються прямо на UI thread без перетину JS-моста.

Приклад: parallax scroll header. На базовому Animated.Value при швидкому скролі FPS падає до 40-45 на mid-range Android. На Reanimated з useAnimatedScrollHandler — стабільні 60 fps, тому що весь перерахунок позиції відбувається на UI thread.

Reanimated 3 з useSharedValue, useAnimatedStyle та withSpring/withTiming — стандарт для анімацій у React Native. Gesture Handler v2 щільно інтегрований: useAnimatedGestureHandler замінює PanResponder і теж працює на UI thread.

Чому Lottie може знижувати FPS на Android і як це виправити

Lottie експортує After Effects анімацію в JSON. На iOS з lottie-ios працює стабільно, але на Android при складних ефектах (blur, частинки, градієнти) векторний рендеринг через Canvas призводить до просадок до 30-40 fps. Рішення — або спрощувати анімацію, або використовувати Rive з апаратним рендерингом. Ми тестували: Lottie-файл з розмиттям 5 МБ на Xiaomi Redmi Note 10 дає 48 fps, аналогічна анімація в Rive (.riv 400 КБ) — 60 fps. Rive працює в 1.25 раза швидше на однаковому пристрої, а при складних ефектах — до 4 разів легше за розміром.

Як вибрати між Lottie та Rive для вашого проєкту?

Обидва інструменти вирішують задачу «дизайнер робить анімацію, розробник додає файл». Але принципово по-різному.

Критерій Lottie Rive
Формат JSON векторна анімація Бінарний .riv
Інтерактивність Ні (лінійне відтворення) State Machine, реакції на ввід
Продуктивність Середня (blur/частинки важкі) Апаратний рендеринг Metal/OpenGL
Розмір файлу 2-5 МБ 200-500 КБ
Підтримка платформ iOS, Android, Web, Flutter, RN iOS, Android, Web, Flutter, RN

Вибір простий: статична декоративна анімація (splash screen, onboarding ілюстрації) — Lottie. Інтерактивні UI-елементи зі станами — Rive. Наприклад, кнопка з hover, pressed, loading, success — одна Rive-анімація з чотирма станами проти чотирьох окремих Lottie-файлів. Це зменшує обсяг коду та спрощує підтримку.

Як впровадити анімації Lottie за 4 кроки?

  1. Експорт з After Effects через плагін Bodymovin — отримуєте .json.
  2. Додавання файлу до ресурсів проєкту (assets або drawable).
  3. Ініціалізація плеєра — в iOS використовуйте LOTAnimationView, в Android — LottieAnimationView.
  4. Запуск з параметрамиloopMode, animationSpeed, contentMode. Для складних сценаріїв — кастомний AnimationListener.

На практиці цей підхід працює, але потребує контролю версій Lottie-файлів. Ми рекомендуємо версіонувати їх разом з кодом і тестувати на цільових пристроях.

Spring-фізика та Hero transitions: як досягти природності

Spring-анімація відчувається природньо тому що імітує фізику — масу, жорсткість і демпфування. У SwiftUI: Animation.spring(response:dampingFraction:). В Android Compose: spring(dampingRatio = Spring.DampingRatioMediumBouncy).

Для Hero-переходів (елемент «перелітає» між екранами) на iOS використовуємо UIViewControllerTransitioningDelegate + UIViewControllerAnimatedTransitioning. У SwiftUI — matchedTransitionSource + navigationTransition(.zoom). На Flutter — Hero віджет, який працює з коробки.

Як уникнути типових помилок у Hero transitions?

Анімація починається нормально, але на цільовому екрані елемент «стрибає» в фінальну позицію. Причина — AutoLayout constraints застосовуються до завершення анімації. Рішення: layoutIfNeeded() в блоці анімації або використання transform замість frame-змін. На Flutter — перевіряйте HeroFlightShuttleConfiguration. Також слідкуйте за VSync: на Android при 90 Гц дисплеї Hero-перехід може виглядати смиканим, якщо не виставлений Choreographer.

Таблиця: Строки виконання та типові сценарії

Задача Час Коментар
Базові екранні переходи та мікроінтеракції 1 тиждень Стандартні gesture-driven sheets, каруселі
Lottie/Rive інтеграція з дизайн-системою 3-5 днів Після отримання фінальних файлів
Кастомна інтерактивність з фізикою (сustom sheet, drawer) 1-2 тижні Включає тестування на 4+ пристроях

Що входить в роботу: анімаційний шар під ключ

  • Інтеграція Lottie/Rive-файлів в дизайн-систему
  • Код gesture-driven переходів (bottom sheets, drawers, каруселі)
  • Тестування на реальних пристроях (iOS, Android)
  • Документація з анімацій (архітектура, ключі станів)
  • Підтримка при оновленні дизайну (гарантія 30 днів)

У нас 5+ років досвіду в мобільній розробці, понад 30 проєктів з анімаціями, сертифіковані iOS/Android розробники. Замовте анімації під ключ — перша консультація безкоштовна. Напишіть нам у месенджер, щоб узгодити деталі.

Apple Developer Documentation – UIKit Animations використовується як базова специфікація.