הגדרת האפליקציה ל'תמונה בתוך תמונה'

בתג הפעילות של קובץ AndroidManifest.xml, מבצעים את הפעולות הבאות:

  1. מוסיפים את supportsPictureInPicture ומגדירים אותו כ-true כדי להצהיר שאתם מתכוונים להשתמש ב-PiP באפליקציה.
  2. מוסיפים את configChanges ומגדירים אותו לערך orientation|screenLayout|screenSize|smallestScreenSize כדי לציין שהפעילות מטפלת בשינויים בהגדרות של הפריסה. כך הפעילות לא תושק מחדש כשיהיו שינויים בפריסה במהלך מעברים למצב PIP.

      <activity
        android:name=".SnippetsActivity"
        android:exported="true"
        android:supportsPictureInPicture="true"
        android:configChanges="orientation|screenLayout|screenSize|smallestScreenSize"
        android:theme="@style/Theme.Snippets">

בקוד Compose, מבצעים את הפעולות הבאות:

  1. מוסיפים את התוסף הזה באתר Context. במהלך המדריך נשתמש בתוסף הזה כמה פעמים כדי לגשת לפעילות.
    internal fun Context.findActivity(): ComponentActivity {
        var context = this
        while (context is ContextWrapper) {
            if (context is ComponentActivity) return context
            context = context.baseContext
        }
        throw IllegalStateException("Picture in picture should be called in the context of an Activity")
    }

הוספת תכונת PiP באפליקציה ברקע בגרסאות Android ישנות יותר מ-12

כדי להוסיף את התכונה 'תמונה בתוך תמונה' במכשירים עם גרסת Android 12 ומטה, משתמשים בלחצן addOnUserLeaveHintProvider. כדי להוסיף את התכונה PiP לגרסאות Android ישנות מ-12:

  1. מוסיפים שער גרסאות כדי שהגישה לקוד הזה תהיה רק בגרסאות O עד R.
  2. משתמשים ב-DisposableEffect עם Context בתור המפתח.
  3. בתוך DisposableEffect, מגדירים את ההתנהגות במקרה שהטריגר onUserLeaveHintProvider מופעל באמצעות פונקציית lambda. ב-lambda, קוראים ל-enterPictureInPictureMode() ב-findActivity() ומעבירים את הערך PictureInPictureParams.Builder().build().
  4. מוסיפים את addOnUserLeaveHintListener באמצעות findActivity() ומעבירים את הלוגריתם הבינארי.
  5. ב-onDispose, מוסיפים את removeOnUserLeaveHintListener באמצעות findActivity() ומעבירים את הלוגריתם.

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O &&
    Build.VERSION.SDK_INT < Build.VERSION_CODES.S
) {
    val context = LocalContext.current
    DisposableEffect(context) {
        val onUserLeaveBehavior: () -> Unit = {
            context.findActivity()
                .enterPictureInPictureMode(PictureInPictureParams.Builder().build())
        }
        context.findActivity().addOnUserLeaveHintListener(
            onUserLeaveBehavior
        )
        onDispose {
            context.findActivity().removeOnUserLeaveHintListener(
                onUserLeaveBehavior
            )
        }
    }
} else {
    Log.i("PiP info", "API does not support PiP")
}

הוספת תכונת PiP באפליקציה בזמן יציאה מהאפליקציה בגרסאות Android 12 ואילך

אחרי Android 12, ה-PictureInPictureParams.Builder מתווסף באמצעות משתנה שמוענק לנגן הווידאו של האפליקציה.

  1. יוצרים modifier ומפעילים את onGloballyPositioned. בשלב מאוחר יותר נשתמש בקואורדינטות של הפריסה.
  2. יוצרים משתנה ל-PictureInPictureParams.Builder().
  3. מוסיפים הצהרה if כדי לבדוק אם גרסת ה-SDK היא S ואילך. אם כן, מוסיפים את setAutoEnterEnabled ל-builder ומגדירים אותו ל-true כדי להיכנס למצב PiP בנגיעה. כך האנימציה תהיה חלקה יותר מאשר אם תעבירו את הנתונים דרך enterPictureInPictureMode.
  4. משתמשים ב-findActivity() כדי להתקשר אל setPictureInPictureParams(). קוראים ל-build() ב-builder ומעבירים אותו.

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(true)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}
VideoPlayer(pipModifier)

משתמשים ב-setAspectRatio כדי להגדיר את יחס הגובה-רוחב של חלון PiP

כדי להגדיר את יחס הגובה-רוחב של חלון ה-PiP, אפשר לבחור יחס גובה-רוחב ספציפי או להשתמש ברוחב ובגובה של גודל הסרטון בנגן. אם אתם משתמשים בנגן media3, עליכם לוודא שהנגן לא null ושהגודל של הסרטון בנגן לא שווה ל-[VideoSize.UNKNOWN][6] לפני שמגדירים את יחס הגובה-רוחב.

val context = LocalContext.current

val pipModifier = modifier.onGloballyPositioned { layoutCoordinates ->
    val builder = PictureInPictureParams.Builder()
    if (shouldEnterPipMode && player != null && player.videoSize != VideoSize.UNKNOWN) {
        val sourceRect = layoutCoordinates.boundsInWindow().toAndroidRectF().toRect()
        builder.setSourceRectHint(sourceRect)
        builder.setAspectRatio(
            Rational(player.videoSize.width, player.videoSize.height)
        )
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
        builder.setAutoEnterEnabled(shouldEnterPipMode)
    }
    context.findActivity().setPictureInPictureParams(builder.build())
}

VideoPlayer(pipModifier)

אם אתם משתמשים בנגן בהתאמה אישית, צריך להגדיר את יחס הגובה-רוחב של הנגן באמצעות התחביר הספציפי לנגן. חשוב לזכור שאם הנגן ישתנה במהלך האינטראקציה הראשונית, והיחס של גובה-רוחב לא יהיה בטווח האפשרי, האפליקציה תקרוס. יכול להיות שתצטרכו להוסיף בדיקות לגבי הזמן שבו ניתן לחשב את יחס הגובה-רוחב, בדומה לאופן שבו זה נעשה בנגן media3.