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

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

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

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

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

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

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

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

  • onUserLeaveHint
  • setAutoEnterEnabled
  • onPictureInPictureModeChanged
  • onPictureInPictureUiStateChanged
  • setPictureInPictureParams.

۲. پیکربندی AndroidManifest

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

بخش‌های زیر برخی‌از موارد استفاده معمول از PiP و مراحل پیاده‌سازی لازم را توضیح می‌دهد:

برنامه کتابخانه را از وضعیت فعال یا غیرفعال بودن پیمایش مطلع می‌کند و نسبت ابعادی را تنظیم می‌کند. کتابخانه 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()
            }
        }
    }
}