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







