为应用设置画中画模式

AndroidManifest.xml 文件的 activity 标签中,执行以下操作:

  1. 添加 supportsPictureInPicture 并将其设置为 true,以声明您将在应用中使用画中画模式。
  2. 添加 configChanges 并将其设置为 orientation|screenLayout|screenSize|smallestScreenSize,以指定您的 activity 处理布局配置更改。这样,当在画中画模式转换期间发生布局更改时,您的 activity 不会重新启动。

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

在您的 Compose 代码中,执行以下操作:

  1. Context 上添加此扩展函数。您将在本指南中多次使用此扩展函数来访问 activity。
    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 内部,使用 lambda 定义 onUserLeaveHintProvider 触发时的行为。在 lambda 中,在 findActivity() 上调用 enterPictureInPictureMode(),并传入 PictureInPictureParams.Builder().build()
  4. 使用 findActivity() 添加 addOnUserLeaveHintListener 并传入 lambda。
  5. onDispose 中,使用 findActivity() 添加 removeOnUserLeaveHintListener 并传入 lambda。

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

为 Android 12 及更高版本添加应用退出时进入画中画模式的功能

Android 12 及更高版本,PictureInPictureParams.Builder 是通过一个传递给应用视频播放器的修饰符添加的。

  1. 创建 modifier 并在其上调用 onGloballyPositioned。布局坐标将在后续步骤中使用。
  2. PictureInPictureParams.Builder() 创建一个变量。
  3. 添加一个 if 语句来检查 SDK 是否为 S 或更高版本。如果是,将 setAutoEnterEnabled 添加到构建器并将其设置为 true,以便在滑动时进入画中画模式。这比通过 enterPictureInPictureMode 提供更流畅的动画。
  4. 使用 findActivity() 调用 setPictureInPictureParams()。在 builder 上调用 build() 并将其传入。

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 设置画中画窗口的宽高比

要设置画中画窗口的宽高比,您可以选择特定的宽高比,也可以使用播放器视频尺寸的宽度和高度。如果您正在使用 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 播放器的处理方式。