Реалізація мініплеєра в мобільному застосунку
Міні-плеєр — смужка із назвою треку, кнопками play/pause та прогрес-баром, яка залишається видимою при навігації між екранами. Виглядає просто, але технічно упирається в архітектуру навігації: плеєр повинен жити поза конкретним екраном та не пересоздаватися при переходах.
Архітектурне рішення
Міні-плеєр — не екран, а persistented overlay поверх всього застосунку. Спосіб розміщення залежить від навігаційної системи.
iOS (UIKit). Додаємо міні-плеєр в UITabBarController або UIWindow — він живе на рівні контейнера, не конкретного ViewController. Обмеження: UITabBar займає нижню частину, міні-плеєр розміщуємо прямо над ним, зрушуючи additionalSafeAreaInsets.bottom у всіх VC у табі.
// У користувацькому UITabBarController
override func viewDidLoad() {
super.viewDidLoad()
miniPlayerView = MiniPlayerView()
view.addSubview(miniPlayerView)
NSLayoutConstraint.activate([
miniPlayerView.bottomAnchor.constraint(equalTo: tabBar.topAnchor),
miniPlayerView.leadingAnchor.constraint(equalTo: view.leadingAnchor),
miniPlayerView.trailingAnchor.constraint(equalTo: view.trailingAnchor),
miniPlayerView.heightAnchor.constraint(equalToConstant: 64)
])
// Зрушуємо safe area для дочірніх VC
additionalSafeAreaInsets.bottom = 64
}
iOS (SwiftUI). ZStack у кореневому ContentView із TabView внизу та міні-плеєром поверх через .overlay(alignment: .bottom). Стан плеєра — @EnvironmentObject або @ObservedObject синглтон.
Android (Jetpack Compose). Міні-плеєр у кореневому Scaffold як bottomBar, або через Box поверх NavHost. Стан через ViewModel на рівні NavGraph — переживає навігацію між екранами.
React Native. Компонент міні-плеєра у кореневому App.tsx поверх навігатора. position: 'absolute', bottom: tabBarHeight + жест свайпа вверх для розворачування.
Expand/Collapse анімація
Міні-плеєр повинен розворачуватися в повноекранний плеєр по тапу або свайпу вверх.
iOS. UIPanGestureRecognizer + UIViewPropertyAnimator з interruptibleAnimator. При проміжних станах — fractionComplete анімується пропорційно смішенню пальця. Apple Music робить саме так: повноекранний плеєр — це sheet з detents, міні-плеєр — користувацький presentationController.
Android Compose. BottomSheetScaffold або ModalBottomSheet з користувацькими sheetPeekHeight та sheetContent. При peekHeight — міні-плеєр, при розвернутому стані — повний.
Синхронізація стану
Прогрес-бар, назва треку, обложка — все це повинно оновлюватися в реальному часі незалежно від того, на якому екрані користувач. Єдиний джерело правди — PlayerViewModel / AudioPlayerManager як синглтон з @Published (iOS) або StateFlow (Android). Міні-плеєр підписується на нього, не зберігає локального стану.
Жести та доступність
Свайп вниз на розвернутому плеєрі — закрити/сворнути в міні. Реалізуємо через UIPanGestureRecognizer (iOS) з пороговим значенням translation.y > 100 для підтвердження дії. При неповному свайпу — UIViewPropertyAnimator повертає в вихідне стан.
На Android Compose — swipeable (із accompanist) або anchoredDraggable (Compose 1.6+) з якорями COLLAPSED / EXPANDED. При швидкості жесту > 1000 dp/s — немедленний перехід без анімації.
VoiceOver/TalkBack: міні-плеєр повинен мати accessibilityLabel із поточним треком та accessibilityHint «Натисніть для відкриття повного плеєра». Кнопка паузи в міні-плеєрі — окремий accessibilityElement.
Орієнтири за часом
Міні-плеєр з expand-анімацією на одній платформі — 2–3 дні. Обі платформи з жестовим управлінням — 3–4 дні.







