在 AndroidManifest.xml
文件的 activity 标记中,执行以下操作:
- 添加
supportsPictureInPicture
并将其设置为true
,以声明您将在应用中使用 PiP。 添加
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 代码中,执行以下操作:
- 在
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 之前的版本添加 PiP,请使用 addOnUserLeaveHintProvider
。请按照以下步骤为 Android 12 之前的版本添加画中画功能:
- 添加一个版本门,以便仅在版本 O 到 R 中访问此代码。
- 使用
DisposableEffect
作为键,并将Context
作为值。 - 在
DisposableEffect
中,使用 lambda 定义在触发onUserLeaveHintProvider
时执行的操作。在 lambda 中,对findActivity()
调用enterPictureInPictureMode()
,并传入PictureInPictureParams.Builder().build()
。 - 使用
findActivity()
添加addOnUserLeaveHintListener
并传入 lambda。 - 在
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
。
- 创建一个
modifier
,并对其调用onGloballyPositioned
。布局坐标将在后面的步骤中使用。 - 为
PictureInPictureParams.Builder()
创建一个变量。 - 添加
if
语句以检查 SDK 是否为 S 或更高版本。如果是这样,请将setAutoEnterEnabled
添加到构建器并将其设置为true
,以便在滑动时进入 PiP 模式。与通过enterPictureInPictureMode
进行动画相比,这种方式可以提供更流畅的动画。 - 使用
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
设置 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 播放器执行的操作类似。