☰
react-native-video 的 VideoView 组件完全指南:原生渲染、播放控制、全屏与画中画
2026/9/27 9:10:34 网站建设 项目流程
  • 音视频
  • 移动开发

【免费下载链接】react-native-video

A component for react-native

项目地址:https://gitcode.com/gh_mirrors/re/react-native-video
点击查看免费下载

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类型必填默认值说明
playerVideoPlayer是-管理待显示视频的VideoPlayer实例
styleViewStyle否-标准 React Native 样式,控制VideoView的布局与外观
controlsboolean否false是否显示原生播放控件(播放/暂停、进度条、音量等)
pictureInPictureboolean否false是否启用并显示原生控件中的画中画(PiP)按钮(需平台支持且控件可见)
autoEnterPictureInPictureboolean否false播放开始后 App 进入后台时是否自动进入 PiP 模式(行为因平台而异)
resizeMode'contain' \| 'cover' \| 'stretch' \| 'none'否'none'视频如何缩放以适配视图
keepScreenAwakeboolean否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)架构。

  1. 原生视图的绑定:VideoView渲染时实际挂载的是NativeVideoView(NativeVideoView.tsx),它通过UIManager.hasViewManagerConfig('VideoView')检测原生视图是否已正确链接,若未链接会抛出包含「pod install / rebuild / Expo Go」排查提示的LINKING_ERROR。

  2. 视图管理器的创建:组件首次挂载后,原生侧会通过onNitroIdChange事件把原生生成的nitroId回传,随后由VideoViewViewManagerFactory.createViewManager(id)创建对应的原生视图管理器(VideoView.tsx)。源码中特别处理了「视图在原生管理器找到它之前就被卸载」的竞态场景,此时只打印警告而非抛错。

  3. Props 的同步:每次 props 变化都会调用updateProps,把player、controls、pictureInPicture、autoEnterPictureInPicture、resizeMode、keepScreenAwake、surfaceType同步到原生管理器(VideoView.tsx)。注意其中player是通过(props.player as VideoPlayer).__getNativePlayer()取出的原生播放器句柄,这正是「同一个播放器可被多个视图共用」的实现基础。

  4. 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

项目地址:https://gitcode.com/gh_mirrors/re/react-native-video
点击查看免费下载

相关推荐

上一篇:终极指南:ChunJun三大高级功能详解——DDL同步、断点续传与脏数据处理
下一篇:5分钟快速上手:轻量级Java工作流引擎Snaker完全指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询