Настройте свое приложение для PiP

В теге activity вашего файла AndroidManifest.xml выполните следующие действия:

  1. Добавьте supportsPictureInPicture и задайте для него значение true чтобы объявить, что вы будете использовать в своем приложении функцию «картинка в картинке» (PiP).
  2. Добавьте configChanges и задайте ему значение orientation|screenLayout|screenSize|smallestScreenSize , чтобы указать, что ваша операция обрабатывает изменения конфигурации макета. Таким образом, ваша операция не будет перезапускаться при изменении макета во время переходов в режиме «картинка в картинке».
<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")
    }

Добавьте приложение «Картинка в картинке при выходе» для устройств на базе Android до 12

Чтобы добавить режим «Картинка в картинке» для устройств на базе Android до 12, используйте addOnUserLeaveHintProvider . Чтобы добавить режим «Картинка в картинке» для устройств на базе Android до 12, выполните следующие действия:

  1. Добавьте шлюз версий, чтобы этот код был доступен только в версиях O до R.
  2. Используйте DisposableEffect с Context в качестве ключа.
  3. Внутри DisposableEffect определите поведение при срабатывании onUserLeaveHintProvider с помощью лямбда-выражения. В лямбда-выражении вызовите 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 = Runnable {
            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")
}

Добавьте приложение «Картинка в картинке при выходе» для устройств после Android 12

После Android 12 PictureInPictureParams.Builder добавляется через модификатор, который передается в видеоплеер приложения.

  1. Создайте modifier и вызовите для него onGloballyPositioned . Координаты макета будут использованы на следующем этапе.
  2. Создайте переменную для PictureInPictureParams.Builder() .
  3. Добавьте оператор if для проверки версии SDK (S или более поздней). Если да, добавьте setAutoEnterEnabled в конструктор и установите его в true чтобы активировать режим «картинка в картинке» при смахивании. Это обеспечивает более плавную анимацию, чем при использовании 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.

Чтобы задать соотношение сторон окна «картинка в картинке», вы можете либо выбрать конкретное соотношение сторон, либо использовать ширину и высоту видео плеера. Если вы используете проигрыватель Media3, убедитесь, что плеер не имеет значение NULL и что размер видео плеера не равен VideoSize.UNKNOWN , прежде чем настраивать соотношение сторон.

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.