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 با پخش پسزمینه تفاوت دارد زیرا ویدیو همچنان روی صفحه نمایش داده میشود و نه فقط در جریان صوتی پخش میشود. پخش پسزمینه (background audio) در هر دو پلتفرم در دسترس است، اما 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 — callback onPictureInPictureModeChanged را.
پنجره PiP محدودیتهای قابل توجهی دارد: نمیتوان عناصر کنترل استاندارد UI (دکمه مکث، نوار پیشرفت) را روی آن نمایش داد — فقط یک روکش سیستمی حداقلی با عناصر پایه: play/pause، بستن، بزرگنمایی به تمام صفحه. رابط کاربری سیستمی PiP در iOS شامل دکمه مکث و بستن است و در Android — همان عناصر به علاوه یک دکمه تنظیمات اضافی. تعامل با محتوای داخل PiP (عقب و جلو بردن، انتخاب زیرنویس) امکانپذیر نیست — برای این کار باید برنامه را به تمام صفحه باز کنید.
در iOS PiP از طریق فریمورک AVKit و کلاس AVPictureInPictureController پیادهسازی شده است. این API در iOS 14+ برای iPhone و iPad در دسترس است، اما با الزامات متفاوت: در iPad PiP از طریق AVPlayerLayer کار میکند، در iPhone — فقط از طریق AVPlayerViewController.
برای کار PiP در iOS باید چند شرط برآورده شود: برنامه باید از AVPlayer برای پخش ویدیو استفاده کند، جلسه صوتی باید روی دسته .playback یا .playAndRecord تنظیم شود و برنامه باید دارای مجوزهای صوتی پسزمینه (UIBackgroundModes = audio) باشد. بدون این تنظیمات PiP راهاندازی نمیشود — سیستم درخواست ایجاد جلسه PiP را رد میکند، زیرا نمیتواند پخش صحیح را پس از انتقال به پسزمینه تضمین کند.
در iOS پنجره PiP به طور خودکار هنگام کوچکسازی برنامه نمایش داده میشود اگر ویدیو به طور فعال در حال پخش باشد و کاربر این ویژگی را در تنظیمات غیرفعال نکرده باشد. کاربر همچنین میتواند به صورت دستی ویدیو را از طریق دکمه موجود در AVPlayerViewController به PiP کوچک کند. اندازه پنجره 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 پس از بررسی isPictureInPictureSupported با playerLayer مقداردهی اولیه میشود (PiP در iPhone SE نسل اول و برخی iPadهای با حافظه ناکافی پشتیبانی نمیشود). delegate به برنامه درباره شروع و پایان PiP اطلاع میدهد — در این callbackها باید عناصر 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 را هنگام کوچکسازی برنامه فعال میکند. callback onPictureInPictureModeChanged هنگام ورود و خروج از PiP فراخوانی میشود — در آن باید عناصر UI را پنهان یا نمایش دهید. برای ویدیو در SurfaceView لازم است پیکربندی اضافی با افزودن android:configChanges="screenSize|smallestScreenSize" در مانیفست انجام شود تا از بازسازی Activity در انتقال به حالت PiP جلوگیری شود.
PiP ابزاری قدرتمند برای بهبود تجربه کاربری در برنامههایی است که محتوا حتی هنگام جابجایی به وظایف دیگر مرتبط باقی میماند. با این حال پیادهسازی PiP باید موجه باشد و کاربر را پرت نکند.
تماسهای تصویری و کنفرانسها — یکی از اصلیترین سناریوهای PiP. در Zoom، FaceTime، Google Meet PiP امکان دیدن مخاطب را هنگام کار در سایر برنامهها فراهم میکند: خواندن یادداشتها، مشاهده ارائه یا بررسی ایمیل. PiP برای تماسهای تصویری نیاز به پشتیبانی دوربین در پسزمینه و تنظیم صحیح جلسه صوتی برای ادامه ضبط صدا در پسزمینه دارد. در 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 را پشتیبانی کنند، اما با عملکرد کاهشیافته.
بله، مدیریت چرخه عمر بسیار مهم است. در iOS هنگام انتقال به PiP برنامه اعلان willStart را دریافت میکند که در آن باید UI را پنهان کرده و حافظه را آزاد کنید. در Android onPictureInPictureModeChanged در ورود/خروج از PiP فراخوانی میشود. در صورت مدیریت نادرست چرخه عمر، سیستم ممکن است برنامه را از حافظه تخلیه کرده و پخش را قطع کند.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید