Проблема: ваш мобільний додаток потребує механіки Stories — зникаючого контенту. Але реалізація таких елементів, як прогрес-бари з плавною анімацією, навігація по тапу, пауза при утриманні, свайп для закриття, попереднє завантаження медіа без затримок та серверний таймер на 24 години, є нетривіальною. Помилка в будь-якому з цих компонентів руйнує користувацький досвід. Ми розробляємо Stories для iOS, Android та крос-платформ. Наш досвід — 10+ років мобільної розробки, понад 50 реалізованих проєктів. Оцінимо ваш проєкт безкоштовно.
Як ми реалізуємо прогрес-бари та навігацію
Горизонтальні прогрес-бари вгорі — UIView з анімацією frame.width через CADisplayLink (iOS) або ValueAnimator (Android). CADisplayLink дає 60/120 FPS синхронізацію з екраном — анімація плавна. Використовувати Timer.scheduledTimer не рекомендується: він смикається, особливо при навантаженні. Тривалість однієї stories — для фото зазвичай 5–7 секунд, для відео — довжина кліпу (але не більше 15 секунд). Прогрес-бар для відео синхронізуємо з AVPlayer.currentTime() через addPeriodicTimeObserver, а не з системним таймером.
Навігація: тап у праву половину екрана — наступна stories, у ліву — попередня. UITapGestureRecognizer з перевіркою location.x > bounds.width / 2. Утримання — UILongPressGestureRecognizer з minimumPressDuration: 0.1: при .began паузимо анімацію та AVPlayer, при .ended — відновлюємо. Swipe вниз для закриття — інтерактивний dismiss через UIPanGestureRecognizer. Масштабування та переміщення екрана вслід за жестом (transform), при відпусканні — або повне закриття (dismiss), або повернення (UIViewPropertyAnimator).
Чому попереднє завантаження медіа критичне?
Затримка при перемиканні stories — головний UX-баг. Користувач тапає — чекає 1–2 секунди, поки завантажується фото або відео. Правильне рішення: попередньо завантажувати наступні 2–3 stories. Для фото — SDWebImage.prefetchURLs() або Kingfisher ImagePrefetcher. Для відео — AVAsset.loadValuesAsynchronously(forKeys: ["playable"]) + AVPlayerItem створюємо заздалегідь, AVPlayer не запускаємо до показу. На Android — Coil ImageLoader.enqueue(ImageRequest) для фото-попереднього завантаження, ExoPlayer з ConcatenatingMediaSource для відео: додаємо наступний елемент у чергу, ExoPlayer попередньо завантажує буфер. Кешуємо попередньо завантажені ресурси в пам'яті (не тільки на диску) — повторний перегляд stories у межах сесії має бути миттєвим. В одному з наших проєктів така оптимізація дозволила зменшити затримки з 2 с до 0.2 с.
Створення stories: від фото до відео
Фото — PHPickerViewController + опціональний редактор (текст, стікери). Текст поверх зображення: UITextView поверх UIImageView, при збереженні — об'єднуємо в UIGraphicsImageRenderer. Стікери — UIView з UIPanGestureRecognizer + UIPinchGestureRecognizer + UIRotationGestureRecognizer.
Відео — запис через AVCaptureSession прямо в stories-камері (як в Instagram/Snapchat) або вибір з галереї. Запис з обмеженням 15 секунд — AVCaptureMovieFileOutput.maxRecordedDuration. Утримання кнопки для запису, відпускання — стоп. Після створення — upload у фоні. Stories з'являється в стрічці одразу з placeholder, замінюється на реальний контент після завантаження.
Як працює таймер зникнення?
24-годинний таймер — на стороні сервера, не клієнта. Клієнт просто запитує список актуальних stories. Сервер фільтрує по created_at + 24h < now. На клієнті для вже завантажених stories з кешу — перевіряємо expiresAt при відкритті. Якщо минув — не показуємо кеш, запитуємо сервер (або видаляємо з локального сховища). Перегляди — відмічаємо на сервері через окремий API-запит після показу stories. Батчимо відмітки: не один запит на кожен перегляд, а накопичуємо за сесію і відправляємо при згортанні додатка або кожні 30 секунд.
Типові помилки при реалізації Stories
| Помилка | Наслідок | Рішення |
|---|---|---|
Використання Timer для прогрес-бару |
Смикана анімація, розсинхрон з відео | CADisplayLink на iOS, ValueAnimator на Android |
| Завантаження медіа "на льоту" | Затримки при перемиканні | Попереднє завантаження 2-3 наступних stories |
| Відсутність кешу в пам'яті | Повторні завантаження при поверненні | Кешування в NSCache або LruCache |
Ігнорування expiresAt на клієнті |
Показ застарілих stories | Перевірка часу до показу |
| Одиночні запити переглядів | Навантаження на сервер | Батчинг раз на 30 секунд |
Що входить в роботу
- Документація (API-схеми, діаграми потоків)
- Вихідний код з коментарями
- Доступи до репозиторію, App Store Connect / Google Play Console
- Інтеграція з вашим бекендом (REST/GraphQL)
- Тестування на реальних пристроях (iOS 15+, Android 10+)
- Пост-релізна підтримка 1 місяць
Строки та вартість
Перегляд stories з прогрес-барами, попереднім завантаженням, навігацією та таймером зникнення — 3–4 дні. Створення з камерою, текстом і стікерами + upload — ще 2–3 дні. Вартість розраховується індивідуально після аналізу вашого проєкту. Зв'яжіться з нами — отримайте консультацію та попередню оцінку.
| Компонент | Час (дні) |
|---|---|
| Механіка перегляду (прогрес-бари, жести, таймер) | 3-4 |
| Попереднє завантаження та кешування медіа | 2-3 |
| Створення stories (камера, редактор, upload) | 2-3 |
| Інтеграція з бекендом та тестування | 2-3 |
| Разом | 7-10 |
Детальніше про механіку stories можна прочитати в App Store Review Guidelines (Section 4.2 та 5.1) та документації Google Play.
Наша команда — 10+ років досвіду в мобільній розробці, гарантуємо якість та дотримання строків. Замовте розробку stories у своєму додатку — оцінимо проєкт за 1 день.







