如何在React Native中实现带实时日期更新的PIP(画中画)模式?
React Native 实现带实时日期更新的画中画(PIP)模式
如果第三方库不好用,直接基于原生模块实现是更可靠的方案,以下是针对Android的完整实现步骤(iOS方案附后):
Android 端实现
1. 配置 AndroidManifest.xml
在你的主 Activity 标签中添加 PIP 支持属性,并声明权限:
<activity android:name=".MainActivity" android:supportsPictureInPicture="true" android:resizeableActivity="true" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"> <!-- Android 12+ 需声明权限 --> <uses-permission android:name="android.permission.USE_PICTURE_IN_PICTURE" /> </activity>
2. 编写原生 PIP 模块
创建 Kotlin 模块,实现进入 PIP 的方法,并在 PIP 模式下每秒发送日期更新事件:
Kotlin 示例(PipModule.kt)
package com.yourappname import android.app.PictureInPictureParams import android.os.Build import android.os.Handler import android.os.Looper import android.util.Rational import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactContextBaseJavaModule import com.facebook.react.bridge.ReactMethod import com.facebook.react.modules.core.DeviceEventManagerModule import java.text.SimpleDateFormat import java.util.* class PipModule(reactContext: ReactApplicationContext) : ReactContextBaseJavaModule(reactContext) { private val handler = Handler(Looper.getMainLooper()) private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()) private val updateRunnable = object : Runnable { override fun run() { val currentDate = dateFormat.format(Date()) // 发送事件到 JS 层 reactApplicationContext .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java) .emit("onPipDateUpdate", currentDate) handler.postDelayed(this, 1000) } } override fun getName() = "PipModule" @ReactMethod fun enterPip() { currentActivity?.let { activity -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val params = PictureInPictureParams.Builder() .setAspectRatio(Rational(16, 9)) // 自定义宽高比 .build() activity.enterPictureInPictureMode(params) } } } override fun onActivityPaused() { super.onActivityPaused() // 检查是否处于 PIP 模式,启动定时器 currentActivity?.let { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && it.isInPictureInPictureMode) { handler.post(updateRunnable) } } } override fun onActivityResumed() { super.onActivityResumed() // 退出 PIP 时停止定时器 handler.removeCallbacks(updateRunnable) } }
注册模块(Package.kt)
package com.yourappname import com.facebook.react.ReactPackage import com.facebook.react.bridge.NativeModule import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.uimanager.ViewManager class PipPackage : ReactPackage { override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> { return listOf(PipModule(reactContext)) } override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> { return emptyList() } }
然后在 MainApplication.kt 中注册这个 Package:
override fun getPackages(): List<ReactPackage> { return PackageList(this).packages.apply { add(PipPackage()) } }
React Native JS 层实现
1. 监听日期更新并渲染UI
import React, { useState, useEffect } from 'react'; import { View, Text, Button, NativeEventEmitter, NativeModules } from 'react-native'; const { PipModule } = NativeModules; const pipEmitter = new NativeEventEmitter(PipModule); const PipScreen = () => { const [currentDate, setCurrentDate] = useState(new Date().toLocaleString()); useEffect(() => { // 监听原生发送的日期更新事件 const subscription = pipEmitter.addListener('onPipDateUpdate', (date) => { setCurrentDate(date); }); return () => subscription.remove(); }, []); const enterPipMode = async () => { try { await PipModule.enterPip(); } catch (err) { console.error('进入PIP模式失败:', err); } }; return ( <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <Text style={{ fontSize: 20, marginBottom: 20 }}>{currentDate}</Text> <Button title="进入画中画模式" onPress={enterPipMode} /> </View> ); }; export default PipScreen;
iOS 端补充方案
iOS 的 PIP 原生支持主要针对视频播放,但如果要显示自定义UI,需要将组件渲染到 AVPlayerLayer 中,或者使用 iOS 15+ 的 UIWindowScene PIP 能力:
- 配置
Info.plist添加UISupportsPictureInPicture为YES - 使用
AVPictureInPictureController承载自定义视图,通过定时器更新日期并刷新图层
不过相对 Android 来说,iOS 自定义 PIP UI 的复杂度更高,建议优先保证 Android 端实现,再针对 iOS 做适配。
内容的提问来源于stack exchange,提问作者Suraj Deshmane
相关产品推荐
相关产品推荐

