- 音视频
- 移动开发
【免费下载链接】react-native-video
A component for react-native
VideoView是 react-native-video v7 中负责把VideoPlayer实例渲染到屏幕上的核心原生视图组件,同时内置了原生播放控件、全屏与画中画(PiP)等 UI 能力。本文以 VideoView 官方文档 为骨架,结合本仓库的 TypeScript 实现与 Nitro 原生绑定源码,系统讲解它的基本用法、全部 Props、命令式方法(Ref)、UI 事件回调、Chapters 章节功能,以及它在 iOS / Android / Web 三端的底层工作原理,让你能直接照着写出可运行的视频播放界面。
VideoView 在 v7 架构中的定位
在 v7 的「播放器模型(Player Model)」中,播放逻辑与视图渲染被明确拆分:
VideoPlayer:负责视频源管理、播放、暂停、seek、音量、字幕等全部播放行为(见 useVideoPlayer 指南 与 VideoPlayer 类文档);VideoView:只负责把某个VideoPlayer的画面渲染到屏幕上,并提供原生控件、全屏、画中画、屏幕常亮等视图层功能。
这意味着你可以把同一个player实例挂到多个VideoView上,也可以在列表页、详情页之间复用一个播放器而无需重建原生资源。使用VideoView的硬性前提是:必须把一个VideoPlayer实例通过playerprop 传入。
基本用法:从创建播放器到渲染画面
最基础的使用方式,是通过useVideoPlayer钩子创建播放器实例,再把它传给VideoView的playerprop:
import React from 'react'; import { VideoPlayer, VideoView } from 'react-native-video'; import { StyleSheet } from 'react-native'; const App = () => { const player = useVideoPlayer('https://example.com/video.mp4', (_player) => { // 可选:播放器创建完成后立即执行的初始化函数 _player.play(); }); return ( <VideoView style={styles.video} player={player} controls={true} /> ); }; const styles = StyleSheet.create({ video: { width: '100%', height: 200, }, }); export default App;几个关键点:
useVideoPlayer的第二个参数是「创建回调」,在播放器实例创建完成后触发,适合在这里调用play()、设置muted、loop等初始状态;controls决定是否显示原生播放控件(播放/暂停、进度条、音量等),默认false,即「裸画面」;player是必填 prop,类型为VideoPlayerBase,见 VideoViewProps.ts。
如果你需要更精细地控制播放器生命周期,也可以不依赖钩子,直接手动创建VideoPlayer实例后传入(参见 VideoPlayer 类文档)。
Props 全量参考
以下表格是VideoView支持的全部 Props,来自 props.md,并与源码中VideoViewProps接口(VideoViewProps.ts)一一对应:
| Prop | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
player | VideoPlayer | 是 | - | 管理待显示视频的VideoPlayer实例 |
style | ViewStyle | 否 | - | 标准 React Native 样式,控制VideoView的布局与外观 |
controls | boolean | 否 | false | 是否显示原生播放控件(播放/暂停、进度条、音量等) |
pictureInPicture | boolean | 否 | false | 是否启用并显示原生控件中的画中画(PiP)按钮(需平台支持且控件可见) |
autoEnterPictureInPicture | boolean | 否 | false | 播放开始后 App 进入后台时是否自动进入 PiP 模式(行为因平台而异) |
resizeMode | 'contain' \| 'cover' \| 'stretch' \| 'none' | 否 | 'none' | 视频如何缩放以适配视图 |
keepScreenAwake | boolean | 否 | true | 视频视图挂载期间是否保持屏幕常亮 |
surfaceType | 'surface' \| 'texture' | 否(仅 Android) | 'surface' | (Android)底层原生视图类型,iOS 上忽略 |
关于resizeMode四种取值的精确定义,源码注释(VideoViewProps.ts)给出如下语义:
'contain':保持宽高比,把视频完整缩放进视图内部(可能留黑边);'cover':保持宽高比并填满整个视图(可能裁剪画面);'stretch':拉伸填满视图,不保持宽高比(画面可能变形);'none':不做任何缩放。
注意:VideoView的默认resizeMode是'none',这与旧版组件的习惯不同,如果发现画面没有按预期适配,请显式设置该 prop。
Android:如何选择 surfaceType
:::info 仅 AndroidsurfaceType只在 Android 生效,iOS 上会被忽略。 :::
在 Android 上,默认渲染路径使用SurfaceView(即surfaceType="surface"),以获得最优的解码性能与更低的延迟。但SurfaceView运行在独立的窗口层(separate window)中,因此它无法:
- 被 transform 动画处理(缩放、旋转、透明度渐隐);
- 被父视图裁剪(圆角、遮罩);
- 与兄弟视图可靠地叠放(存在 z-order 问题)。
如果你的 UI 需要上述效果,应切换为TextureView:
<VideoView player={player} surfaceType="texture" style={{ width: 300, height: 170, borderRadius: 16, overflow: 'hidden' }} resizeMode="cover" controls />使用原则:仅在确实需要动画、圆角裁剪或重叠 UI 时才用TextureView,因为它性能略低,且在部分设备上可能增加功耗。相关类型定义可参见 VideoViewViewManager.nitro.ts。
Refs 与命令式方法:程序化控制全屏与画中画
VideoView通过forwardRef暴露命令式方法(VideoView.tsx)。获取 ref 后即可调用:
const videoViewRef = React.useRef<VideoViewRef>(null); // ... <VideoView ref={videoViewRef} player={player} /> // 之后即可调用命令式方法: videoViewRef.current?.enterFullscreen();VideoViewRef上可用的方法(定义见 methods.md 与 VideoViewProps.ts):
| 方法 | 类型 | 说明 |
|---|---|---|
enterFullscreen() | () => void | 程序化请求进入全屏模式 |
exitFullscreen() | () => void | 程序化请求退出全屏模式 |
enterPictureInPicture() | () => void | 程序化请求进入画中画模式 |
exitPictureInPicture() | () => void | 程序化请求退出画中画模式 |
canEnterPictureInPicture() | () => boolean | 检查画中画当前是否可用/受支持,可进入返回true,否则返回false |
另外,VideoViewRef还暴露了一个addEventListener方法(见 VideoViewProps.ts),可以像下面这样以编程方式注册 UI 事件监听,并返回一个可调remove()的订阅对象:
const subscription = videoViewRef.current?.addEventListener( 'onFullscreenChange', ({ isFullscreen }) => { console.log(isFullscreen ? '进入全屏' : '退出全屏'); } ); // 不再需要时移除监听 subscription?.remove();从实现上看,这些命令式方法都会转发给底层的 NitroVideoViewViewManager混合对象(VideoViewViewManager.nitro.ts),并由一个wrapNativeViewManagerFunction包装器统一处理「视图管理器未找到」等错误(VideoView.tsx)。
事件回调:感知全屏与画中画状态变化
VideoView接受一系列与 UI 状态变化相关的事件回调(完整列表见 events.md,事件类型定义见 Events.ts):
| 事件 | 类型 | 说明 |
|---|---|---|
onPictureInPictureChange? | (event: { isActive: boolean }) => void | 画中画开始或停止时触发 |
onFullscreenChange? | (event: { isFullscreen: boolean }) => void | 全屏开始或停止时触发 |
willEnterFullscreen? | () => void | 即将进入全屏前触发 |
willExitFullscreen? | () => void | 即将退出全屏前触发 |
willEnterPictureInPicture? | () => void | 即将进入画中画前触发 |
willExitPictureInPicture? | () => void | 即将退出画中画前触发 |
这些回调可以用于在状态切换时同步更新组件自身的 UI 或业务状态:
<VideoView player={player} onFullscreenChange={({ isFullscreen }) => { console.log(isFullscreen ? 'Entered fullscreen' : 'Exited fullscreen'); }} onPictureInPictureChange={({ isActive }) => { console.log(isActive ? 'PiP active' : 'PiP inactive'); }} />在 VideoView.tsx 中可以看到,这些基于 prop 的回调会被自动注册为原生事件监听器(addOnFullscreenChangeListener、addWillEnterPictureInPictureListener等),并在依赖变化或组件卸载时通过sub.remove()正确清理,避免内存泄漏;组件卸载时还会调用clearAllListeners()(VideoView.tsx)。
Chapters:进度条章节标记与跳转
VideoView还支持「视频章节」功能:章节会以可视化标记显示在 seekbar 上,用户点击即可跳到对应位置。该功能属于 Pro 插件能力(对应文档 frontmatter 标注plan: pro),仓库提供了演示视频 chapters.mp4 展示实际效果。
安装与启用
首先安装独立插件包:
npm install @react-native-video/chapters然后在应用初始化时调用enable()开启该功能,必须在调用其他章节方法之前执行:
import { enable } from '@react-native-video/chapters'; enable();setChapters:设置章节列表
setChapters(chapters, options?)用于为播放器设置章节。chapters是如下结构的对象数组:
{ title: string; // 章节标题 timeMs: number; // 章节时间点(毫秒) }[]可选的options配置对象支持:
markersColor?: string—— 章节标记的颜色(默认取平台默认色);showTooltip?: boolean—— 悬停在标记上时是否显示提示气泡(默认true);showTimer?: boolean—— 是否在标记上显示时间(默认true)。
完整示例:
import { setChapters } from '@react-native-video/chapters'; const chapters = [ { title: "Introduction", timeMs: 0 }, { title: "Main Content", timeMs: 30000 }, // 30 秒 { title: "Conclusion", timeMs: 120000 }, // 2 分钟 ]; setChapters(chapters, { markersColor: "#FF6B35", showTooltip: true, showTimer: true, });clearChapters 与 goToChapter
clearChapters()移除播放器上的所有章节:
import { clearChapters } from '@react-native-video/chapters'; clearChapters();goToChapter(title)按标题程序化跳转到指定章节:
import { goToChapter } from '@react-native-video/chapters'; goToChapter("Main Content");平台差异
- iOS:自定义 seekbar,带可视标记与提示气泡;
- Android:seekbar 上的可视标记,支持提示气泡。
源码层面:VideoView 是如何驱动原生渲染的
理解 Props 与方法的背后,是本仓库基于 Nitro 的混合对象(Hybrid Object)架构。
原生视图的绑定:
VideoView渲染时实际挂载的是NativeVideoView(NativeVideoView.tsx),它通过UIManager.hasViewManagerConfig('VideoView')检测原生视图是否已正确链接,若未链接会抛出包含「pod install / rebuild / Expo Go」排查提示的LINKING_ERROR。视图管理器的创建:组件首次挂载后,原生侧会通过
onNitroIdChange事件把原生生成的nitroId回传,随后由VideoViewViewManagerFactory.createViewManager(id)创建对应的原生视图管理器(VideoView.tsx)。源码中特别处理了「视图在原生管理器找到它之前就被卸载」的竞态场景,此时只打印警告而非抛错。Props 的同步:每次 props 变化都会调用
updateProps,把player、controls、pictureInPicture、autoEnterPictureInPicture、resizeMode、keepScreenAwake、surfaceType同步到原生管理器(VideoView.tsx)。注意其中player是通过(props.player as VideoPlayer).__getNativePlayer()取出的原生播放器句柄,这正是「同一个播放器可被多个视图共用」的实现基础。iOS / Android 的实现载体:iOS 侧对应
HybridVideoViewViewManager.swift等文件(见 ios/hybrids/VideoViewViewManager),Android 侧由 Kotlin 实现并在 fabric 原生组件 中提供渲染载体,两者都遵循 VideoViewViewManager.nitro.ts 定义的接口契约。
Web 端实现差异
Web 平台的VideoView走的是另一套实现(VideoView.web.tsx),基于@videojs/react的 Player 与 VideoSkin:
resizeMode被映射为 CSSobject-fit:'contain' → contain、'cover' → cover、'stretch' → fill、'none' → contain(VideoView.web.tsx);- 全屏通过
containerRef.current?.requestFullscreen?.()/document.exitFullscreen?.()实现,画中画通过video.requestPictureInPicture?.()/document.exitPictureInPicture?.()实现,canEnterPictureInPicture返回document.pictureInPictureEnabled; controls={true}时使用VideoSkin包裹画面以呈现控制 UI。
因此同样的 Props 与命令式方法在 Web 上也能获得一致的使用体验。
实战建议与相关文档
- 播放器生命周期:推荐始终用
useVideoPlayer创建播放器,它会在组件卸载时自动释放原生资源(详见 use-video-player.md),避免在VideoView卸载后仍持有已释放的播放器。 - 全屏与 PiP 的组合:若需要「进入后台自动画中画」,可同时开启
autoEnterPictureInPicture,并结合onPictureInPictureChange更新 UI;在调用enterPictureInPicture()前,建议先用canEnterPictureInPicture()探测设备支持度。 - 性能取舍:Android 默认的
surface渲染路径性能最优,仅当确实需要圆角、动画或叠层 UI 时才切换到texture。 - 联动查阅:播放行为与事件在 player/events.md 中有完整对照;想了解 v6 旧版组件与 v7 的差异,可参考 updating.md。
- 音视频
- 移动开发
【免费下载链接】react-native-video
A component for react-native
相关推荐
react-native-video 的 VideoView 组件 Props 全解析:播放器绑定、原生控件、画中画与画面适配
react native video 的 VideoView 组件 Props 全解析:播放器绑定、原生控件、画中画与画面适配 导读 VideoView 是 r
音视频移动开发Hydra核心架构解析:如何实现实时3D场景图构建与优化
Hydra核心架构解析:如何实现实时3D场景图构建与优化 Hydra 是一个革命性的实时3D场景图构建系统,由麻省理工学院SPARK实验室开发。这个强大的机器人
计算机视觉深度学习Windows 11终极清理指南:使用Win11Debloat实现系统性能优化与隐私保护
Windows 11终极清理指南:使用Win11Debloat实现系统性能优化与隐私保护 Windows 11虽然带来了现代化的界面和功能,但同时也带来了预装应
桌面应用CLI
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考