画中画 (Picture-in-Picture)
源:画中画支持
画中画 (PiP) 是一种特殊的多窗口模式,最常用于视频播放。当用户按下 Home 键时,应用会缩小成一个小窗口悬浮在屏幕上。
1. 清单配置
xml
<activity
android:name=".VideoActivity"
android:supportsPictureInPicture="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" />2. 进入 PiP 模式
在 Activity 中(或者通过 ContextWrapper),调用 enterPictureInPictureMode。
kotlin
// 在 VideoPlayer Composable 中
val context = LocalContext.current
val activity = context as? Activity
// 监听 App 切到后台 (如按下 Home 键)
DisposableEffect(lifecycleOwner) {
val observer = LifecycleEventObserver { _, event ->
if (event == Lifecycle.Event.ON_PAUSE) {
// 尝试进入 PiP 模式而不是暂停
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val params = PictureInPictureParams.Builder()
.setAspectRatio(Rational(16, 9))
.build()
activity?.enterPictureInPictureMode(params)
}
}
}
lifecycleOwner.lifecycle.addObserver(observer)
onDispose { lifecycleOwner.lifecycle.removeObserver(observer) }
}3. 适配 PiP UI
当应用处于 PiP 模式时,应该隐藏播放控制条等无关 UI,只保留视频画面。
我们可以监听 LocalConfiguration 并没有直接提供 PiP 状态,通常我们需要在 Activity 中监听 onPictureInPictureModeChanged 并通过 CompositionLocal 或 State 传递给 Compose。
kotlin
// 1. 定义 LocalPipMode
val LocalPipMode = compositionLocalOf { false }
// 2. 在 Activity 中分发
class VideoActivity : ComponentActivity() {
var isInPipMode by mutableStateOf(false)
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
isInPipMode = isInPictureInPictureMode
}
override fun onCreate(...) {
setContent {
CompositionLocalProvider(LocalPipMode provides isInPipMode) {
VideoScreen()
}
}
}
}
// 3. 在 UI 中响应
@Composable
fun VideoScreen() {
val inPip = LocalPipMode.current
Box {
VideoPlayer()
// 如果不在 PiP 模式,显示控制条
if (!inPip) {
VideoControls()
}
}
}