Користувач завершив квест, отримав 500 монет — і додаток показує нудний AlertDialog з "Вітаємо, +500". Момент втрачено. Нагорода має відчуватися фізично: частинки конфетті, лічильник, що біжить з прискоренням, тактильний відгук у момент піку. Без цього гейміфікація перетворюється на формальність.
Ми проектуємо reward popup, який перетворює технічну подію на емоцію. За 5 років на ринку реалізували більше 50 гейміфікаційних проектів — від стартапів до enterprise. Наші сертифіковані інженери використовують нативні анімації (SwiftUI/UIKit, Jetpack Compose), Core Haptics, CAEmitterLayer. Попап запускається за 1.2–2 секунди — якщо довше, користувач починає тапати «закрити». В одному fintech-проекті заміна стандартного Alert на reward popup з анімацією лічильника та haptic збільшила конверсію повторних дій на 27% за тиждень.
Чому звичайний AlertDialog не підходить для нагородження?
Alert — це вікно з інформацією. Reward popup — це мікросценарій з кульмінацією, розрядкою та зворотним зв'язком. Alert не підтримує staggered-анімацію, частинки або haptic. У ньому немає лічильника, який створює ефект «накопичення». Адже саме ці деталі збільшують конверсію повторних дій на 20–30% (дані A/B-тестів наших проектів).
Анатомія reward popup
Типова структура по шарах:
- Backdrop: затемнення фону з blur-ефектом (UIBlurEffect / RenderEffect.createBlurEffect)
- Card: поява знизу або масштабом з пружинною анімацією
- Reward icon: scale + rotation з bounce
- Particle burst: конфетті, зірочки, монети — CAEmitterLayer або Lottie
- Text reveal: лічильник балів, що анімується від попереднього значення до нового
- CTA button: з'являється із затримкою після основної анімації
Ключові елементи: Backdrop з blur, Particle burst з конфетті та анімований лічильник. Весь пайплайн займає 1.2–2 секунди. Довше — користувач починає тапати «закрити».
Як реалізувати анімований лічильник на iOS?
Найдокладніший елемент — анімований лічильник. +500 монет має рахуватися, а не просто з'являтися.
class CountingLabel: UILabel { func countFrom(_ start: Int, to end: Int, duration: TimeInterval) { let displayLink = CADisplayLink(target: self, selector: #selector(update)) self.start = start; self.end = end self.startTime = CACurrentMediaTime() self.duration = duration displayLink.add(to: .main, forMode: .common) } @objc func update(link: CADisplayLink) { let elapsed = CACurrentMediaTime() - startTime let progress = min(elapsed / duration, 1.0) let eased = 1 - pow(1 - progress, 3) // ease-out cubic currentValue = Int(Double(start) + Double(end - start) * eased) text = "+\(currentValue)" if progress >= 1 { link.invalidate() } } } У Flutter — TweenAnimationBuilder
Particle burst: CAEmitterLayer vs Lottie
CAEmitterLayer у 2–3 рази продуктивніший за Lottie при рендерингу частинок, але потребує більше коду. Нижче порівняння:
| Параметр | CAEmitterLayer | Lottie |
|---|---|---|
| Продуктивність | Висока (нативний рендеринг) | Середня (рендеринг JSON) |
| Розмір | ~50 КБ | 200+ КБ |
| Гнучкість | Повний контроль частинок | Обмежений анімацією |
| Кросплатформність | Тільки iOS | iOS, Android, Web |
Для однократного burst конфетті при появі попапа — CAEmitterLayer з birthRate = 300 на перші 0.1 секунди, потім birthRate = 0. Це дає ефект «вибуху» без нескінченного потоку.
emitterLayer.birthRate = 1 // включено DispatchQueue.main.asyncAfter(deadline: .now() + 0.15) { emitterLayer.birthRate = 0 // вимкнено — частинки летять до кінця lifetime } Lottie-конфетті — простіший шлях: готовий .json файл відтворюється однократно поверх попапа. CAEmitterLayer продуктивніший, але потребує коду. Core Haptics — офіційна документація для тактильних ефектів.
Що таке staggered анімація і чому вона важлива?
Усе має з'являтися не одночасно — stagger створює відчуття «розгортання» нагороди. Кожен елемент має свою таймінг-лінію:
| Час | Подія |
|---|---|
| 0ms | Backdrop з'являється, blur наростає |
| 150ms | Card влітає знизу (spring) |
| 300ms | Particle burst |
| 350ms | Icon scale up з bounce |
| 500ms | Haptic feedback (success) |
| 600ms | Текст нагороди fade in |
| 800ms | Лічильник починає рахувати |
| 1200ms | CTA кнопка з'являється |
На iOS — DispatchQueue.main.asyncAfter для кожного етапу або UIViewPropertyAnimator з addAnimations(afterDelay:). У Flutter — AnimationController + Interval curves для кожного елемента.
Як додати конфетті з CAEmitterLayer? (покроково)
- Створіть CAEmitterLayer і встановіть його frame рівним bounds попапа.
- Налаштуйте emitterCells: задайте вміст (наприклад, прямокутник з кольором), birthRate, lifetime, velocity, scale, spin.
- Встановіть birthRate = 1 на 0.15 секунди, потім обнуліть (як у коді вище).
- Додайте шар як sublayer до view попапа.
- Перевірте, що частинки встигають відмалюватися до dismiss (lifetime ~0.8 с).
Зв'яжіться з нами для оцінки вашого проекту — ми безкоштовно проаналізуємо ваш сценарій нагородження. Замовте розробку reward popup під ключ і отримайте консультацію з гейміфікації додатку.
Що входить в роботу
- Аналіз сценарію користувача та дизайн попапа
- Реалізація на Swift (iOS) або Kotlin (Android) з використанням нативних анімацій
- Інтеграція haptic feedback (Core Haptics / Vibrator)
- Підключення аналітики (Firebase / AppsFlyer)
- Документація та передача вихідного коду
- Підтримка протягом 30 днів після здачі
Гарантуємо коректну роботу на всіх пристроях — протестовано на 20+ моделях. Термін: від 1 дня для стандартного reward popup з анімаціями та haptic на одній платформі.







