Розробка Reels (короткі відео) в мобільній програмі
Reels — вертикальна стрічка відео з автовідтворенням при скролингу. Технічно один з найскладніших UI-паттернів у мобільній розробці: гладкий paging-скролинг, предзагрузка відео, плеєр з синхронізованим звуком, нескінченна стрічка з пагінацією. Кожен із цих компонентів можна реалізувати так, щоб працював без затримок — або так, щоб знищив UX.
Вертикальний paging-скролинг
Основа Reels — UICollectionView з UICollectionViewCompositionalLayout + UICollectionLayoutSectionOrthogonalScrollingBehavior.paging (iOS) або RecyclerView з PagerSnapHelper (Android). Кожен елемент займає весь екран (bounds.size).
На iOS пагінаційний скролинг через UICollectionView з isPagingEnabled = true — працює, але не дає контролю над deceleration. Краще: кастомний UICollectionViewFlowLayout з переопределенням targetContentOffset(forProposedContentOffset:withScrollingVelocity:), що snap'ає до найближчого відео з потрібною анімацією.
Velocity-based переключення: швидкий свайп переключає на наступний Reel незалежно від того, наскільки далеко проскролили. sqrt(velocity.x² + velocity.y²) > threshold → snap до наступного елемента.
Плеєр та переключення між відео
Критичне рішення: один shared AVPlayer або плеєр на ячейку?
Один shared AVPlayer з переназначенням AVPlayerItem при скролингу — стандартний підхід для Reels. При scrollViewDidEndDecelerating заберіть плеєр з попередної ячейки та назначьте поточній. AVPlayerLayer.player = avPlayer — миттєво. Плеєр не пересоздається — переключення без пауз.
На Android — один ExoPlayer на всю активність/фрагмент. PlayerView.player = exoPlayer переназначає. Використовуйте MediaItem з preload: exoPlayer.addMediaItem(nextMediaItem) для наступного відео — ExoPlayer починає буферизацію до фактичного переключення.
Предзагрузка: тримайте у пам'яті AVPlayerItem для поточного, наступного та попереднього відео. Створення AVPlayerItem з URL займає час — робіть це при початку скролу до сусідного елемента, не при завершенні.
func collectionView(_ collectionView: UICollectionView,
willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) {
// Предзагружаємо AVPlayerItem для цього індексу
let item = AVPlayerItem(url: videoURLs[indexPath.row])
playerItemCache[indexPath.row] = item
}
Запис коротких відео
Камера для запису Reels — кастомна AVCaptureSession. AVCaptureVideoPreviewLayer відображає live preview на весь екран. Запис через AVCaptureMovieFileOutput з обмеженням: maxRecordedDuration = CMTime(seconds: 60, preferredTimescale: 600).
Мультисегментна запис (кілька коротких кліпів в один Reel) — на кожну запис створіть окремий AVAsset, в кінці об'єднайте через AVMutableComposition. AVMutableCompositionTrack.insertTimeRange() вставляє сегменти послідовно.
Фільтри в реальному часі — Core Image з CIFilter застосовуйте до CMSampleBuffer у методі делегата captureOutput(_:didOutput:from:). Рендеріть через CIContext з Metal (CIContext(mtlDevice: MTLCreateSystemDefaultDevice()!)). OpenGL для цієї задачі у 2025 році — застарілий підхід з гіршою продуктивністю.
Звук, текст, ефекти
Аудіотрек — своя музика з медіатеки через MPMediaPickerController (iOS) або ACTION_PICK з MediaStore.Audio (Android), або треки з каталогу програми. Накладайте аудіо на відео через AVMutableComposition з двома треками: відео + аудіо.
Текст поверх відео — не UILabel поверх UIImageView, а запеканання у відео через AVVideoCompositionCoreAnimationTool + CATextLayer. Це дає корректне відображення тексту при експорті та публікації.
Продуктивність стрічки
UICollectionView.prefetchDataSource на iOS — запитуйте метаданні наступних 3 відео при скролингу. RecyclerView.setRecycledViewPool() на Android — спільний пул view для переповторення, зменшує число inflate-операцій.
Пам'ять: тримайте декодовані AVPlayerItem максимум для 5 сусідніх відео. При подальшому скролингу — звільніть AVPlayerItem.asset явно. Без цього при перегляді 20+ Reels пам'ять виростає до 300–500 МБ і iOS відправляє memory warning.
| Компонент | Складність | Приблизний час |
|---|---|---|
| Вертикальний paging + shared плеєр | Висока | 2–3 дні |
| Предзагрузка + кеш | Середня | 1–2 дні |
| Запис + мультисегменти | Висока | 3–4 дні |
| Фільтри real-time (Core Image) | Висока | 2–3 дні |
| Текст + аудіо в експорті | Середня | 2 дні |
Часові рамки
Перегляд стрічки з автовідтворенням, предзагрузкою та пагінацією — 1–2 тижні. Повний цикл (запис, редагування, фільтри, публікування, стрічка) — 3–6 тижнів залежно від набору функцій. Вартість розраховується після аналізу вимог.







