Picture-in-Picture (PiP) — це режим відтворення відео в плаваючому вікні поверх інших застосунків, що дозволяє користувачеві продовжувати перегляд контенту при згортанні застосунку або перемиканні між програмами. PiP-вікно автоматично позиціонується в кутку екрана і може бути переміщене користувачем. За даними Apple AVPictureInPictureController documentation (2026), PiP-режим підтримується на iOS починаючи з версії 14 і на Android з версії 8.0.
Головне
Picture-in-Picture (PiP) — це режим відображення відео в маленькому плаваючому вікні, яке залишається поверх усіх інших вікон і застосунків. Користувач може переміщувати вікно PiP по екрану, змінювати його розмір (на деяких платформах) і продовжувати перегляд контенту під час роботи в інших застосунках.
Концепція PiP прийшла з телебачення: ще в 1990-х роках телевізори дозволяли показувати другий канал у кутку екрана. На мобільних пристроях PiP вперше з'явився на iPad в iOS 9 (2015 рік) для відео в Safari, а повноцінний системний PiP для застосунків став доступним в iOS 14 (2020). На Android підтримка PiP з'явилася раніше — у версії 8.0 Oreo (2017), але тільки для відео, а починаючи з Android 12 — для будь-яких типів контенту.
PiP відрізняється від фонового відтворення тим, що відео продовжує відображатися на екрані, а не тільки відтворюватися в аудіопотоці. Фонове відтворення доступне на обох платформах, але PiP дає користувачеві візуальний контроль над контентом: він бачить кадри, може поставити на паузу, перемотати або закрити вікно. Це особливо важливо для відеоуроків, стрімів і відеодзвінків, де візуальний контент не менш важливий, ніж аудіо.
Архітектурно PiP реалізується через системний менеджер вікон, який створює окреме вікно з пониженим пріоритетом відображення. Застосунок делегує відеовихід системному сервісу, який продовжує рендеринг відео навіть після того, як застосунок переходить у фоновий режим або згортається.
Процес починається, коли користувач згортає застосунок з активним відео або натискає кнопку PiP (на iOS) або система автоматично переводить Activity у режим PiP (на Android). Системний менеджер вікон захоплює відеопотік і створює плаваюче вікно з фіксованими пропорціями. Розмір вікна залежить від співвідношення сторін вихідного відео та обмежень платформи: на iOS PiP-вікно займає приблизно 1/6–1/4 ширини екрана, на Android — не менше 108 dp в ширину та 240 dp у висоту для мобільних пристроїв.
Коли PiP-вікно активне, застосунок може перебувати в одному з трьох станів: у фоні (згорнуто), в активному стані (користувач повернувся до застосунку), або в стані очікування (система призупинила PiP через нестачу ресурсів). При переході в PiP застосунок повинен призупинити непотрібні UI-операції (анімації, рендеринг інтерфейсу) і звільнити пам'ять, оскільки системні ресурси в багатозадачному режимі розподіляються більш жорстко. iOS автоматично надсилає застосунку сповіщення AVPictureInPictureControllerWillStartNotification, а Android — колбек onPictureInPictureModeChanged.
PiP-вікно має суттєві обмеження: на ньому не можна відображати стандартні UI-елементи керування (кнопки паузи, повзунок прогресу) — тільки мінімальний системний оверлей з базовими елементами: play/pause, закрити, розгорнути на повний екран. Системний UI PiP на iOS включає кнопку паузи та закриття, а на Android — ті самі елементи плюс додаткову кнопку для налаштувань. Взаємодія з контентом всередині PiP (перемотка, вибір субтитрів) неможлива — для цього потрібно розгорнути застосунок на повний екран.
На iOS PiP реалізований через фреймворк AVKit та клас AVPictureInPictureController. Цей API доступний на iOS 14+ для iPhone та iPad, але з різними вимогами: на iPad PiP працює через AVPlayerLayer, на iPhone — тільки через AVPlayerViewController.
Для роботи PiP на iOS необхідно виконати кілька умов: застосунок повинен використовувати AVPlayer для відтворення відео, audio session має бути налаштована на категорію .playback або .playAndRecord, і застосунок повинен мати entitlements для фонового аудіо (UIBackgroundModes = audio). Без цих налаштувань PiP не запуститься — система відхилить запит на створення сесії PiP, оскільки не зможе гарантувати коректне відтворення після переходу у фоновий режим.
На iOS PiP-вікно автоматично показується при згортанні застосунку, якщо відео активно відтворюється і користувач не вимкнув цю функцію в налаштуваннях. Користувач може також вручну згорнути відео в PiP через кнопку в AVPlayerViewController. Розмір PiP-вікна на iOS фіксований і визначається системою — розробник не може його змінити. Співвідношення сторін PiP-вікна відповідає співвідношенню сторін вихідного відео, але максимальний розмір обмежений 1/4 ширини екрана на iPhone та 1/3 на iPad.
Основні обмеження PiP на iOS: неможливість кастомного UI в PiP-вікні, обмеження на один PiP-потік одночасно та вимога активного AVPlayer для роботи PiP. Multi-PiP — одночасне відтворення кількох PiP-вікон — не підтримується на iOS. При спробі запустити другий PiP перший автоматично закривається. Це обмеження апаратне: відеопроцесор не може одночасно обслуговувати два незалежних PiP-канали через обмеження DMA та відеопам'яті.
Ще одне важливе обмеження — тривалість відтворення у фоні. Якщо користувач не взаємодіє з PiP-вікном, система може призупинити відтворення через деякий час для економії енергії. Автоматична пауза PiP на iOS настає через 10–15 хвилин неактивності, якщо застосунок не реалізував keep-alive механізм через background task. Для відеодзвінків і стрімів рекомендується використовувати PushKit та VoIP-сертифікати, які обходять це обмеження.
На Android PiP реалізований як вбудований режим Activity, який активується через метод enterPictureInPictureMode. Починаючи з Android 8.0 (API 26), будь-яка Activity може перейти в PiP-режим, а з Android 12 (API 31) з'явилася підтримка PiP для SurfaceView та TextureView без необхідності використання MediaCodec.
Для підтримки PiP у маніфесті Android необхідно вказати атрибут android:supportsPictureInPicture для Activity у розділі
В Android PiP-вікно за замовчуванням не має елементів керування. Розробник може додати кастомні дії через RemoteAction у методі setPictureInPictureParams. Доступно до 3 дій (наприклад: пауза/плей, перемотка назад/вперед, закриття). Кожна дія відображається в системному оверлеї PiP у вигляді іконки. На відміну від iOS, де всі UI-елементи строго фіксовані, Android дає більше гнучкості для базових контролів.
PiP на Android має різні можливості залежно від версії ОС. На Android 8.0–8.1 PiP доступний тільки для відео, що відтворюється через MediaPlayer або MediaCodec з SurfaceView. Починаючи з Android 9, можна використовувати PictureInPictureArgs.Builder для налаштування співвідношення сторін PiP-вікна. Android 12 додав підтримку PiP для кастомних SurfaceView та TextureView, а також покращене керування переходами між повноекранним та PiP-режимом. Android 13+ дозволяє відображати PiP-вікно навіть при заблокованому екрані, якщо застосунок має відповідний дозвіл.
| Версія Android | Можливості PiP | API |
|---|---|---|
| 8.0–8.1 | Базовий PiP для MediaPlayer/MediaCodec | 26–27 |
| 9–11 | Налаштування співвідношення сторін, кастомні дії | 28–30 |
| 12 | Підтримка SurfaceView/TextureView у PiP | 31 |
| 13+ | PiP на екрані блокування, покращені анімації | 33+ |
Ключова відмінність Android PiP від iOS — можливість multi-PiP. На Android з версії 12 система може показувати кілька PiP-вікон одночасно, якщо застосунки це підтримують і продуктивність пристрою дозволяє. Однак на практиці multi-PiP обмежений можливостями SoC: більшість пристроїв підтримують тільки одне PiP-вікно через апаратні обмеження декодера, оскільки кожне PiP-вікно вимагає власного відеопотоку та окремого сеансу декодування.
Розглянемо практичну реалізацію PiP на обох мобільних платформах з урахуванням останніх змін API.
import AVKit
import AVFoundation
class VideoPlayerViewController: UIViewController {
var player: AVPlayer!
var pipController: AVPictureInPictureController?
override func viewDidLoad() {
super.viewDidLoad()
let playerLayer = AVPlayerLayer(player: player)
playerLayer.videoGravity = .resizeAspect
view.layer.addSublayer(playerLayer)
guard AVPictureInPictureController.isPictureInPictureSupported()
else { return }
pipController = AVPictureInPictureController(playerLayer: playerLayer)
pipController?.delegate = self
}
@IBAction func startPiPTapped() {
pipController?.startPictureInPicture()
}
}
extension VideoPlayerViewController: AVPictureInPictureControllerDelegate {
func pictureInPictureControllerWillStart(
_ pictureInPictureController: AVPictureInPictureController
) {
// Сховати UI-елементи, звільнити пам'ять
}
func pictureInPictureControllerDidStop(
_ pictureInPictureController: AVPictureInPictureController
) {
// Відновити UI, відновити рендеринг
}
}
У прикладі AVPictureInPictureController ініціалізується з playerLayer після перевірки isPictureInPictureSupported (PiP не підтримується на iPhone SE 1-го покоління та деяких iPad без достатньої пам'яті). Делегат сповіщає застосунок про початок та завершення PiP — у цих колбеках потрібно приховати та відновити UI-елементи, оскільки в PiP-режимі інтерфейс застосунку не видно. При переході в PiP рекомендується зупинити всі анімації, приховати контроли плеєра та звільнити невикористовувану пам'ять для запобігання примусовому вивантаженню застосунку системою.
class PipVideoActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setupVideoPlayer()
}
private fun enterPipMode() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val aspectRatio = Rational(16, 9)
val pipParams = PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.setAutoEnterEnabled(true)
.build()
enterPictureInPictureMode(pipParams)
}
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
if (isInPictureInPictureMode) {
// Сховати UI, фокусуватися тільки на медіа
binding.controlsGroup.visibility = View.GONE
} else {
// Відновити UI
binding.controlsGroup.visibility = View.VISIBLE
}
}
}
Приклад на Kotlin використовує PictureInPictureParams.Builder для налаштування PiP. Метод setAspectRatio задає співвідношення сторін PiP-вікна (16:9 для типового відео). setAutoEnterEnabled(true) вмикає автоматичний перехід у PiP при згортанні застосунку. Колбек onPictureInPictureModeChanged викликається при вході та виході з PiP — у ньому слід приховувати або показувати UI-елементи. Для відео на SurfaceView потрібно додатково обробити конфігурацію, додавши android:configChanges="screenSize|smallestScreenSize" в маніфест, щоб запобігти перестворенню Activity при переході в PiP-режим.
PiP — потужний інструмент для покращення користувацького досвіду в застосунках, де контент залишається релевантним навіть при перемиканні на інші завдання. Однак впровадження PiP має бути обґрунтованим і не відволікати користувача.
Відеодзвінки та конференції — один із головних сценаріїв PiP. У Zoom, FaceTime, Google Meet PiP дозволяє бачити співрозмовника під час роботи з іншими застосунками: читання нотаток, перегляду презентації або перевірки пошти. PiP для відеодзвінків вимагає підтримки камери у фоновому режимі та правильного налаштування audio session для продовження захоплення аудіо у фоні. На iOS для цього використовується AVSampleBufferDisplayLayer замість AVPlayerLayer, оскільки відеодзвінки не використовують AVPlayer.
Стрімінгові сервіси (YouTube, Netflix, Twitch) активно використовують PiP для продовження перегляду під час пошуку нового контенту. YouTube Premium пропонує PiP як платну функцію, Netflix також обмежує PiP певними тарифними планами через ліцензійні обмеження контенту. Для реалізації PiP у стрімінговому застосунку потрібна інтеграція з DRM-системою (FairPlay, Widevine), яка підтримує безпечний pipeline у PiP-режимі.
PiP не підходить для застосунків з інтерактивним відеоконтентом, де потрібна взаємодія користувача: освітні платформи з тестами всередині плеєра, ігрові стріми з чатом, застосунки для покупок із посиланнями на товари у відео. У цих випадках PiP-вікно занадто мале для відображення додаткової інформації, а інтерактивні елементи в PiP не підтримуються системою. Рекомендується використовувати PiP тільки для пасивного перегляду, коли взаємодія з контентом не потрібна.
Для музичних та подкаст-застосунків PiP надлишковий — достатньо фонового аудіо без візуального вікна. PiP споживає додаткові ресурси GPU для рендерингу відео в плаваючому вікні, що скорочує час автономної роботи. Якщо контент аудіальний (музика, подкасти, аудіокниги) — використовуйте фонове відтворення без PiP. Якщо візуальний — впроваджуйте PiP для покращення користувацького досвіду.
Часті запитання
PiP на iOS вимагає iPhone 6s+, iOS 14+ та регіон з підтримкою (США, Канада, Австралія, ЄС, Росія та інші). Для застосунку необхідно налаштувати audio session на категорію .playback і додати UIBackgroundModes = audio. Також перевірте налаштування: Налаштування > Основні > Картинка в картинці.
На iOS розмір PiP-вікна повністю визначається системою і не налаштовується розробником. На Android можна задати тільки співвідношення сторін через setAspectRatio в PictureInPictureParams.Builder, але точний розмір вікна визначає система. Користувач може змінити розмір PiP-вікна на Android 12+ жестом pinch-to-zoom.
Так, PiP працює з DRM-захищеним контентом (FairPlay на iOS, Widevine L1 на Android) за умови, що DRM-сесія підтримує захищений pipeline в PiP-режимі. Widevine L3 може не підтримувати PiP, оскільки не гарантує безпеку декодованого контенту в плаваючому вікні. Перевіряйте сумісність DRM з PiP на етапі тестування.
На iOS — тільки одне PiP-вікно. На Android 12+ теоретично підтримується multi-PiP, але на практиці більшість пристроїв обмежені одним вікном через апаратні обмеження. Топ-пристрої (Samsung Galaxy S24, Pixel 8) можуть підтримувати 2 PiP-вікна, але з пониженою продуктивністю.
Так, обробка lifecycle критично важлива. На iOS при переході в PiP застосунок отримує сповіщення willStart, де потрібно приховати UI і звільнити пам'ять. На Android onPictureInPictureModeChanged викликається при вході/виході з PiP. При невірній обробці lifecycle система може вивантажити застосунок з пам'яті, перервавши відтворення.
Підсумки
Ми розробимо мобільний застосунок під ключ
IT Sectr створює застосунки для iOS та Android для стартапів і бізнесу з 2017 року. Ми проконсультуємо вас і запропонуємо найкраще рішення.
Читайте також