استفاده از «کتابخانه تصویردرتصویر Jetpack»

کتابخانه Jetpack تصویردرتصویر (PiP) راه‌حلی ساده و قدرتمند برای توسعه‌دهندگان برنامه Android ارائه می‌دهد تا عملکرد PiP را پیاده‌سازی کنند، به‌ویژه برای برنامه‌های پخش رسانه، ارتباط ویدیویی، و ناوبری. این کتابخانه با ارائه یک میانای برنامه‌سازی کاربردی یکپارچه به حذف کد متن استاندارد و اشکالات رایج درون‌برنامه کمک می‌کند و کیفیت کلی تجربه کاربری «تصویردرتصویر» را بهبود می‌بخشد.

کتابخانه PiP Jetpack با پرداختن به چندین چالش کلیدی و ناهماهنگی در سراسر بوم‌سازگان Android، میاناهای برنامه‌سازی کاربردی PiP موجود را تسهیل می‌کند:

  • تکه‌تکه‌سازی سیستم‌عامل: کتابخانه به‌طور خودکار تفاوت‌های موجود در فراخوانی‌های PiP API را در نسخه‌های مختلف Android مدیریت می‌کند، مانند استفاده از enterPictureInPictureMode قبل‌از Android 12 و isAutoEnterEnabled بعداز آن، بنابراین توسعه‌دهندگان نیازی به مدیریت تفاوت‌های نسخه ندارند.
  • پارامترهای PiP نادرست: این ویژگی راه‌حلی یکپارچه برای تنظیم صحیح پارامترهای PiP، برای مثال setSourceRectHint، ارائه می‌دهد تا پویانمایی‌های روان و باکیفیت درطول بازپخش رسانه ایجاد شود.
  • بازخوانی‌های وضعیت «تصویر در تصویر» یکپارچه: onPictureInPictureModeChanged و onPictureInPictureUiStateChanged را در یک میانای بازخوانی یکپارچه (PictureInPictureDelegate.OnPictureInPictureEventListener) ادغام می‌کند تا مدیریت وضعیت و میانای کاربر ساده‌تر شود.
  • کاهش کد متن استاندارد: این کتابخانه با ارائه مجموعه‌های ازپیش‌تعریف‌شده RemoteActions برای موارد استفاده رایج، مانند کنترل‌های بازپخش و کنش‌های تماس تصویری، میزان کد متن استاندارد تکراری را کاهش می‌دهد.
  • سازگاری با آینده: ویژگی‌های بیشتر «تصویر در تصویر» ازطریق کتابخانه Jetpack ارائه می‌شود و به پذیرندگان امکان می‌دهد با حداقل تلاش یا بدون تلاش به عملکردهای اضافی دسترسی داشته باشند.

گردش کار انتقال

دسته مورد استفاده برنامه و منطق PiP قدیمی را شناسایی کنید:

دسته‌ها: بازپخش ویدیو، پیمایش، یا تماس تصویری.

منطق PiP قدیمی برای شناسایی:

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams.

۲. پیکربندی AndroidManifest

مطمئن شوید «فعالیت» واردشده به 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»، پیاده‌سازی سفارشی «تصویر در تصویر» موجود را با «میاناهای برنامه‌سازی کاربردی کتابخانه Jetpack» جایگزین کنید. پیچیدگی و هزینه پذیرش براساس پیاده‌سازی فعلی برنامه متفاوت خواهد بود.

بخش‌های زیر برخی‌از موارد استفاده معمول از «تصویر در تصویر» و مراحل پیاده‌سازی لازم را شرح می‌دهند:

برنامه وضعیت فعال یا غیرفعال بودن پیمایش را به کتابخانه اطلاع می‌دهد و نسبت ابعادی را تنظیم می‌کند. کتابخانه Jetpack بقیه کار را انجام می‌دهد.

تفاوت‌های اساسی:

  1. نیازی به متمایز کردن ورود خودکار و ورود قدیمی در سمت برنامه نیست.
  2. میاناهای بازخوانی یکپارچه شدند.
  3. سازنده جدید PictureInPictureParams برای سازگاری با نسخه قدیمی.

تماس تصویری

برنامه وضعیت فعال یا غیرفعال تماس را به کتابخانه اطلاع می‌دهد و نسبت ابعادی را تنظیم می‌کند.

تفاوت‌های اساسی:

  1. نیازی به متمایز کردن ورود خودکار و ورود قدیمی در سمت برنامه نیست.
  2. میاناهای بازخوانی یکپارچه شدند.
  3. سازنده جدید PictureInPictureParams برای سازگاری با نسخه قدیمی.
  4. نمادهای کنش استانداردشده برای تماس تصویری.

۵. انتقال کد

  • منطق ورودی: منطق مختص میانای برنامه‌سازی کاربردی مثل setAutoEnterEnabled برای Android 12 و بالاتر، یا onUserLeaveHint برای Android 11 و پایین‌تر را با setEnabled جایگزین کنید. هرزمان وضعیت واجدشرایط بودن PiP تغییر کرد، این را راه‌اندازی کنید.
  • پاسخ‌های تماس: onPictureInPictureModeChanged (تغییر وضعیت چیدمان) و onPictureInPictureUiStateChanged (پویانمایی/وضعیت‌ها) را در یک پاسخ تماس رویدادمحور یکپارچه onPictureInPictureEvent ادغام کنید.
  • کنش‌ها و پارامترها: پارامترها را بااستفاده از setActions و setAspectRatio در نمونه الگو هر زمان که تغییر کردند به‌روز کنید.

الگوهای پیاده‌سازی مرجع

نمونه‌هایی از پیاده‌سازی‌ها.

ناوبری و تماس تصویری

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()
            }
        }
    }
}