کتابخانه Jetpack تصویر در تصویر (PiP) یک راه حل ساده و قوی برای توسعه دهندگان برنامه های اندروید ارائه می دهد تا قابلیت PiP را به ویژه برای پخش رسانه، ارتباط تصویری و برنامه های ناوبری پیاده سازی کنند. این کتابخانه با ارائه یک API یکپارچه، به حذف کدهای تکراری و اشکالات رایج درون برنامه ای کمک می کند و کیفیت کلی تجربه کاربری PiP را بهبود می بخشد.
کتابخانه PiP Jetpack با پرداختن به چندین چالش کلیدی و ناسازگاری در اکوسیستم اندروید، APIهای PiP موجود را تسهیل میکند:
- پراکندگی سیستم عامل : این کتابخانه به طور خودکار تفاوتهای موجود در فراخوانیهای PiP API را در نسخههای مختلف اندروید، مانند استفاده از
enterPictureInPictureModeقبل از اندروید ۱۲ وisAutoEnterEnabledبعد از آن، مدیریت میکند، بنابراین توسعهدهندگان نیازی به مدیریت تفاوتهای نسخه ندارند. - پارامترهای نادرست PiP : این یک راه حل یکپارچه برای تنظیم صحیح پارامترهای PiP، به عنوان مثال
setSourceRectHint، برای ایجاد انیمیشنهای روان و با کیفیت بالا در حین پخش رسانه ارائه میدهد. - فراخوانیهای وضعیت یکپارچه PiP : این روش
onPictureInPictureModeChangedوonPictureInPictureUiStateChangedرا در یک رابط فراخوانی واحد و یکپارچه (PictureInPictureDelegate.OnPictureInPictureEventListener) برای مدیریت سادهتر وضعیت و رابط کاربری، ادغام میکند. - کاهش کدهای تکراری : این کتابخانه با ارائه مجموعههای از پیش تعریفشدهای از
RemoteActionsبرای موارد استفاده رایج، مانند کنترلهای پخش و اقدامات تماس ویدیویی، میزان کدهای تکراری و تکراری را کاهش میدهد. - آیندهنگر : ویژگیهای بیشتر PiP از طریق کتابخانه Jetpack ارائه میشود و به کاربران اجازه میدهد تا با حداقل تلاش یا بدون هیچ تلاشی به قابلیتهای اضافی دسترسی پیدا کنند.
گردش کار مهاجرت
دسته بندی موارد استفاده برنامه و منطق PiP قدیمی را مشخص کنید:
دستهها: پخش ویدیو، ناوبری یا تماس ویدیویی.
منطق PiP قدیمی برای شناسایی:
-
onUserLeaveHint -
setAutoEnterEnabled -
onPictureInPictureModeChanged -
onPictureInPictureUiStateChanged -
setPictureInPictureParams.
۲. پیکربندی AndroidManifest
اطمینان حاصل کنید که Activity وارد شده در PiP، پشتیبانی را در AndroidManifest.xml با configChanges لازم اعلام میکند تا از راهاندازی مجدد غیرضروری جلوگیری شود:
<activity
android:name="VideoActivity" android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>
۳. تنظیمات محیطی
وابستگیهای مورد نیاز را به build.gradle اضافه کنید:
dependencies {
implementation("androidx.core:core:1.18.0")
implementation("androidx.activity:activity:1.13.0")
implementation("androidx.core:core-pip:1.0.0-alpha02") }
برای وابستگیها از جدیدترین کتابخانههای AndroidX استفاده کنید و برای اطلاعات بیشتر به صفحه انتشارها مراجعه کنید.
۴. انتخاب الگو و مقداردهی اولیه
الگوی پیادهسازی را انتخاب کنید که به بهترین وجه با مورد استفاده برنامه مطابقت داشته باشد:
- پیمایش و تماس ویدیویی :
BasicPictureInPicture؛ تغییر اندازه یکپارچه معمولاً پشتیبانی نمیشود و نیازی به اشاره به منبع صحیح ندارید. - پخش ویدیو :
VideoPlaybackPictureInPicture؛ به طور خودکار مرزهای نمای پخشکننده را برای اشاره به منبع مستقیم ردیابی میکند و به طور پیشفرض تغییر اندازه یکپارچه را فعال میکند.
برای استفاده از کتابخانه Jetpack، پیادهسازی PiP سفارشی موجود خود را با APIهای کتابخانه Jetpack جایگزین کنید. پیچیدگی و هزینه استفاده از آن بسته به پیادهسازی فعلی برنامه متفاوت خواهد بود.
بخشهای زیر برخی از موارد استفاده معمول PiP و مراحل پیادهسازی لازم را شرح میدهند:
ناوبری
این برنامه، کتابخانه را از وضعیت فعال یا غیرفعال بودن ناوبری مطلع میکند و نسبت ابعاد را تنظیم میکند. کتابخانه Jetpack بقیه کارها را انجام میدهد.
تفاوتهای کلیدی:
- نیازی به تمایز قائل شدن بین ورود خودکار و ورود قدیمی در سمت برنامه نیست.
- رابطهای فراخوانی یکپارچه.
- سازنده جدید
PictureInPictureParamsبرای سازگاری با نسخههای قبلی.
تماس تصویری
این برنامه، کتابخانه را از وضعیت فعال یا غیرفعال بودن فراخوانی مطلع میکند و نسبت ابعاد را تنظیم میکند.
تفاوتهای کلیدی:
- نیازی به تمایز قائل شدن بین ورود خودکار و ورود قدیمی در سمت برنامه نیست.
- رابطهای فراخوانی یکپارچه.
- سازنده جدید
PictureInPictureParamsبرای سازگاری با نسخههای قبلی. - آیکونهای عملیاتی استاندارد برای تماس ویدیویی.
۵. انتقال کد
- منطق ورود: منطق خاص API مانند
setAutoEnterEnabledبرای اندروید ۱۲ و بالاتر، یاonUserLeaveHintبرای اندروید ۱۱ و پایینتر را باsetEnabledجایگزین کنید. هر زمان که وضعیت واجد شرایط بودن PiP تغییر کند، این فعال میشود. - فراخوانیهای برگشتی:
onPictureInPictureModeChanged(تغییر طرحبندی) وonPictureInPictureUiStateChanged(انیمیشن/وضعیتها) را در یک فراخوانی برگشتی مبتنی بر رویداد یکپارچهonPictureInPictureEventادغام کنید. - اقدامات و پارامترها: پارامترها را با استفاده از
setActionsوsetAspectRatioدر نمونه الگو، هر زمان که تغییر کنند، بهروزرسانی کنید. - مدیریت ویژه ویدیو: برای برنامههای ویدیویی،
setPlayerViewبرای خودکارسازی بهروزرسانیهای راهنمای تصحیح منبع و اطمینان از انتقال روان استفاده کنید. ` ### 6. پاکسازی
برای VideoPlaybackPictureInPicture ، تابع close در onDispose یا onDestroy فراخوانی کنید تا منابعی مانند ردیابهای نما آزاد شوند.
الگوهای پیادهسازی مرجع
نمونههایی از پیادهسازیها
ناوبری و تماس تصویری
class NavOrVideoCallJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener { private lateinit var pictureInPictureImpl: BasicPictureInPicture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) pictureInPictureImpl = BasicPictureInPicture(this) // BasicPictureInPicture is ideal for Navigation and Video call use cases. pictureInPictureImpl.addOnPictureInPictureEventListener( ContextCompat.getMainExecutor(this), this ) setContent { } } override fun onPictureInPictureEvent( event: PictureInPictureDelegate.Event, config: Configuration? ) { when (event) { PictureInPictureDelegate.Event.ENTERED -> { /* Toggle to PiP layout */ } PictureInPictureDelegate.Event.EXITED -> { /* Toggle to Full-screen layout */ } PictureInPictureDelegate.Event.STASHED -> { /* Optional: PiP is stashed */ } PictureInPictureDelegate.Event.UNSTASHED -> { /* Optional: PiP is unstashed */ } } } }
پخش ویدئو
class VideoPlaybackJpipActivity : ComponentActivity(), PictureInPictureDelegate.OnPictureInPictureEventListener { private lateinit var pictureInPictureImpl: VideoPlaybackPictureInPicture override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) pictureInPictureImpl = VideoPlaybackPictureInPicture(this) pictureInPictureImpl.addOnPictureInPictureEventListener( ContextCompat.getMainExecutor(this), this ) setContent { ContentScreen(pictureInPictureImpl) } } override fun onPictureInPictureEvent( event: PictureInPictureDelegate.Event, config: Configuration? ) { when (event) { PictureInPictureDelegate.Event.ENTER_ANIMATION_START -> { /* Hide overlays */ } PictureInPictureDelegate.Event.ENTER_ANIMATION_END -> { /* Animation finished */ } PictureInPictureDelegate.Event.ENTERED -> { /* Switch to PiP layout */ } PictureInPictureDelegate.Event.STASHED -> { /* PiP stashed */ } PictureInPictureDelegate.Event.UNSTASHED -> { /* PiP unstashed */ } PictureInPictureDelegate.Event.EXITED -> { /* Return to full-screen */ } } } @Composable fun ContentScreen(pipController: VideoPlaybackPictureInPicture) { DisposableEffect(pipController) { onDispose { pipController.close() } } } }