Реалізація анімації прогрес-барів та індикаторів у мобільному застосунку
Прогрес-бар — це комунікація. Уявіть застосунок із 500 000 користувачів: після оновлення анімація завантаження стала ривковою, retention впав на 10% за тиждень. Або лінійний прогрес-бар заповнюється до 70% і зависає — користувач думає, що застосунок завис. Анімація тут не прикраса, а функція, що впливає на утримання. Ми накопичили 5+ років досвіду в реалізації анімацій завантаження для iOS, Android та Flutter — від простих спінерів до складних skeleton screens. Наші рішення знижують perceived latency на 30% і підвищують retention на 15% на етапах завантаження. Гарантуємо: після інтеграції користувач не покине застосунок через «завислий» екран. Вартість розробки розраховується індивідуально і залежить від складності проекту.
Як зробити анімацію прогрес-бара плавною?
Прогрес не повинен рухатися лінійно — це виглядає механічно. Використовуємо easing-функції: CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) (ease-out) створює відчуття наростаючої швидкості на початку і плавного завершення. На Android — DecelerateInterpolator(), у Flutter — Curves.easeOut. Для багатоетапного прогресу (завантаження → обробка → збереження) анімуємо кожен етап окремо з мікро-паузою між ними. Критичний нюанс: ніколи не оновлюйте прогрес-бар частіше, ніж раз на 100–200 мс при мережевому завантаженні. Ривкове оновлення кожні 10 мс виглядає гірше, ніж плавне раз на 200 мс з анімацією між значеннями.
Типи індикаторів завантаження
| Тип | iOS | Android | Flutter |
|---|---|---|---|
| Лінійний | CALayer + CABasicAnimation bounds.size.width |
ObjectAnimator.ofInt + DecelerateInterpolator |
TweenAnimationBuilder + LinearProgressIndicator |
| Круговий | CAShapeLayer strokeEnd |
Canvas drawArc + ValueAnimator |
CircularProgressIndicator з AnimationController |
| Skeleton | CAGradientLayer + location анімація |
Shimmer (Facebook) або кастомний Drawable |
shimmer package або кастомний ShaderMask |
Коли який індикатор обрати?
Вибір залежить від сценарію. Для завантаження списку контенту (наприклад, стрічка новин) skeleton screen знижує perceived latency на 20-30% порівняно зі спінером. Для операцій з відомим об'ємом (завантаження файлу) — лінійний прогрес-бар з точним відсотком. Для невідомої тривалості — круговий індикатор (spinner) з плавною пульсацією. У таблиці нижче порівняння за UX-метриками:
| Індикатор | Сприйманий час | Retention | Контекст |
|---|---|---|---|
| Skeleton screen | -30% | +15% | Високий |
| Лінійний з easing | -20% | +10% | Середній |
| Круговий спіннер | 0% | 0% | Низький |
Чому skeleton screen краще спіннера?
Спіннер не дає контексту — користувач не знає, що завантажується. Skeleton screen показує структуру майбутнього контенту, що знижує тривожність. За нашими даними, такий підхід підвищує retention на 15% на етапах завантаження. Ми рекомендуємо skeleton для списків, профілю та новинних стрічок. Реалізуємо через shimmer-ефект: CAGradientLayer з анімацією locations від [-1, -0.5, 0] до [1, 1.5, 2]. На Android — бібліотека Shimmer від Facebook або ValueAnimator + кастомний Drawable. Дослідження показують: skeleton screens зменшують сприйманий час очікування на 20-30% порівняно зі спіннером.
Коли варто використовувати кастомний індикатор?
Якщо бренд вимагає унікального візуального стилю — наприклад, прогрес-бар з градієнтом, анімованою іконкою або нестандартною формою. Кастомний індикатор також необхідний, коли стандартні спіннери не вписуються в інтерфейс (темна тема, складні анімації). У таких випадках ми розробляємо індикатор з нуля, використовуючи CAShapeLayer на iOS, Canvas на Android або CustomPainter у Flutter.
Реалізація на кожній платформі
Лінійний прогрес-бар
На iOS: CALayer з анімацією bounds.size.width через CABasicAnimation. На Android: ObjectAnimator.ofInt(progressBar, "progress", from, to) з setInterpolator(DecelerateInterpolator()) — сповільнення до кінця дає відчуття «майже готово». У Flutter: TweenAnimationBuilder з LinearProgressIndicator(value: progress). Приклад анімації на Swift:
let animation = CABasicAnimation(keyPath: "bounds.size.width")
animation.fromValue = 0
animation.toValue = progress * containerWidth
animation.duration = 0.3
animation.timingFunction = CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94)
progressLayer.add(animation, forKey: "progress")
На Android:
val animator = ObjectAnimator.ofInt(progressBar, "progress", from, to)
animator.interpolator = DecelerateInterpolator()
animator.duration = 300L
animator.start()
Круговий індикатор
CAShapeLayer з strokeEnd на iOS або Canvas + drawArc на Android. Для кастомного дизайну з градієнтом по колу: CAGradientLayer + CAShapeLayer як маска — стандартний, але не очевидний прийом.
Skeleton screens
Замість спіннерів для контентних екранів — skeleton screen. Реалізуємо через shimmer-ефект: CAGradientLayer з анімацією locations від [-1, -0.5, 0] до [1, 1.5, 2]. На Android — бібліотека Shimmer від Facebook або ValueAnimator + кастомний Drawable.
Що входить у роботу
- Аналіз UX та вибір типу індикатора під сценарій
- Реалізація нативної анімації з підтримкою всіх станів (завантаження, помилка, пусто)
- Інтеграція з мережевим шаром та локальними даними
- Тестування на реальних пристроях з різною продуктивністю
- Документація та передача коду, навчання розробників
Процес роботи
- Аналітика — обговорюємо екрани та типи індикаторів, погоджуємо дизайн
- Прототипування — швидкий прототип анімації за 1 день
- Розробка — код з урахуванням архітектури застосунку
- QA — перевірка на пристроях (iOS 15+, Android 10+)
- Деплой — завантаження в App Store / Google Play та моніторинг
Терміни: від 1 дня для стандартного прогрес-бара, до 5 днів для комплексного рішення з skeleton та кастомною анімацією. Оцінюємо проект безкоштовно — зв'яжіться з нами для консультації. Замовте реалізацію індикаторів під ключ — отримайте готовий код з документацією.
Типові помилки та як їх уникнути
- Оновлення прогресу частіше 100 мс — ривкова анімація. Завжди використовуйте таймер з інтервалом.
- Лінійна інтерполяція без easing — виглядає неприродно. Застосовуйте easing-функції.
- Відсутність обробки переривань (наприклад, користувач натиснув назад). Зупиняйте анімацію та звільняйте ресурси.
- Невідповідність кольору/стилю індикатора загальному UI. Погоджуйте дизайн на етапі аналітики.
Ключовий результат: користувач не помічає завантаження, анімація виглядає природно і не дратує. Зв'яжіться з нами для безкоштовної оцінки проекту.







