☰
react-360-common-ui 组件库实战:在 React 360 项目中快速构建视频播放与控制 UI
2026/9/26 13:00:27 网站建设 项目流程
  • 前端
  • 3D渲染

【免费下载链接】react-360

Create amazing 360 and VR content using React

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

react-360-common-ui是 React 360 官方仓库中附带的一个轻量级共享 UI 组件库,专门为任意 react-360 项目提供可直接复用的媒体控制界面(Media Control UIs)。它并不扩展 react-360 运行时本身,而是基于react-360公开的渲染组件与VideoModule原生模块封装出两个高价值组件:VideoPlayer(2D 视频播放屏)与VideoControl(播放/暂停、静音/音量、进度条控制条)。阅读本文后,你将掌握这两个组件的完整 API、底层调用链,并能直接在自己的 React 360 项目中集成一套带自动淡出交互的 VR 视频播放器。

一、组件库概览:它解决什么问题

在 React 360 应用中,播放视频通常需要两条路径:

  • 360 背景视频:通过Environment.setBackgroundVideo把视频贴到全景球上;
  • 2D 平面视频:通过Environment.setScreen把视频纹理贴到某个 Surface 内的一个矩形区域上。

无论哪种路径,播放控制(播放/暂停、进度条、音量、静音)都是重复劳动。react-360-common-ui正是把这些逻辑收敛为一个可复用的 React 组件库。其官方描述为:

react-360-common-uiis a library that contains useful common React Components that can be used in any react-360 project. It generally doesn't extend the react-360 library, but provide useful utilities like Media Control UIs.

该库发布为 npm 包react-360-common-ui(version 0.1.0),其依赖为react@16.3.2、react-native@0.55.4、react-360@1.1.0(见 addons/react-360-common-ui/package.json),意味着它面向 React 360 1.x 时期的项目。库的入口 addons/react-360-common-ui/index.js 只导出两个组件:

module.exports = { VideoPlayer, VideoControl, };

对应源码位于:

  • addons/react-360-common-ui/src/VideoPlayer.react.js —— 视频播放容器组件,负责创建播放器实例并把视频画面贴到 Surface;
  • addons/react-360-common-ui/src/VideoControl.react.js —— 水平控制条组件,负责播放状态、进度与音量的交互。

二、VideoControl:水平媒体控制条

VideoControl是整套组件库的核心交互单元。从源码注释可知(VideoControl.react.js),它“表现为一条水平控制条,可放置在 VideoPlayer 组件(2D 视频)下方,或场景中任意位置(例如用于 360 背景视频时)”,并包含以下 UI 元素:

  • 播放/暂停按钮、取消静音/静音按钮、音量按钮;
  • 进度条与同时显示已播时长和总时长的计时器。

2.1 对外 Props

export type VideoControlProps = { fontSize: number, // 计时文字字号,默认 16 player: ?VideoPlayerInstance, // VideoModule 的播放器实例,必传核心 style: any, // 外部叠加样式 onEnter?: ?() => void, // 指针进入控制条时回调 onExit?: ?() => void, // 指针离开控制条时回调 };

组件内部维护的状态包括音量(初始 1.0)、是否静音(初始 false)、播放状态(初始'loading')、时长(初始 -1)、当前位置(初始 -1),全部来自播放器上报的onVideoStatusChanged事件(见 VideoControl.react.js):

state = { volume: 1.0, isMuted: false, playStatus: 'loading', duration: -1, position: -1, };

组件通过player.addListener('onVideoStatusChanged', ...)订阅状态变化,并在componentWillReceiveProps中处理player属性切换(先移除旧订阅再注册新订阅),在componentWillUnmount中清理订阅,避免事件泄漏。

2.2 交互逻辑(源码级)

四个核心交互回调:

交互回调底层调用
播放/暂停_onPlayButtonClick正在播放则player.pause(),否则player.resume()
静音/取消静音_onMuteButtonClickplayer.setMuted(!isMuted)
音量调整_onVolumeClick(volume)player.setVolume(volume)
进度跳转_onClickProgress(progress)player.seek(duration * progress)

这些方法最终都落到VideoModule上:pause/resume/seek/setVolume/setMuted在 Libraries/VRModules/VideoModule.js 的VideoPlayerInstance中均有定义,它们是对原生VideoModule的 JS 封装。例如seek最终调用NativeVideoModule.seek(player, timeMs),setVolume调用NativeVideoModule.setParams(player, {volume})。

进度条是典型的 VR 凝视交互实现:VideoSliderBar用两个View(填充段barFill与空段barEmpty)按flex比例拼接,分别监听onMove事件,把指针在条上的偏移量换算成 0~1 的进度位置(_onFillMove/_onEmptyMove),指针离开时重置为 -1,只有onClick且已获得有效凝视位置时才触发回调(见 VideoControl.react.js)。

2.3 图标:createGlyph 生成矢量图标

控制条上的图标并非外部图片资源,而是通过createGlyph在运行时以矢量指令生成,见 Libraries/Utilities/createGlyph.js:

function createGlyph(glyph, name) { const uri = 'texture://glyph/' + name; GlyphTextures.registerGlyph(name, glyph); return {uri}; }

播放、暂停、静音图标均由move/line/rect/arc等绘图指令描述,例如播放键是一个三角形:

const IMAGE_PLAY = createGlyph({ width: 128, height: 128, color: '#999999', instructions: [['begin'], ['move', 20, 11], ['line', 108, 64], ['line', 20, 117], ['end']], });

静音图标则是扬声器外形追加一条斜线(concat一组move/line指令,见 VideoControl.react.js)。这意味着组件零外部图片依赖,加载速度快。

2.4 时间格式化

videoTimeFormat(time)(VideoControl.react.js)是导出的小工具:无有效时间返回'--:--';不足 1 小时显示mm:ss;超过 1 小时显示h:mm:ss,且只有在存在小时时才强制分钟两位。渲染层把已播与总长拼成position/duration文本,例如12:34/45:00。

三、VideoPlayer:带控制条的 2D 视频播放组件

VideoPlayer在 React 组件层面完成“创建播放器 → 测量视图位置 → 把视频纹理贴到 Surface → 叠加控制条”的完整闭环,是比手写Environment.setScreen更高级的封装。

3.1 对外 Props 与默认值

type Props = { style?: ViewStyleProp, // 外层容器样式 controlStyle?: ViewStyleProp,// 控制条样式(高度/宽度/透明度可被覆盖) layout?: VideoLayout, // 'RECT' | 'SPHERICAL' | 'CUBEMAP_32' muted: boolean, // 默认 false onPlayerCreated: (player: VideoPlayerInstance) => void, screenId: string, // 默认 'default',对应 Environment.setScreen 的 screenId source: Source, // VideoSource 或 VideoSource 数组 stereo?: VideoStereoFormat, // '2D' | '3DLR' | '3DTB' | '3DBT' | 'UNKNOWN' visible: boolean, // 默认 true,false 时隐藏画面 volume: number, // 默认 1.0 showControl: boolean, // 默认 true,是否显示控制条 };

其中layout、stereo、source的类型定义均来自 Libraries/VRModules/VideoModule.js:VideoLayout为'RECT' | 'SPHERICAL' | 'CUBEMAP_32',VideoStereoFormat为'2D' | '3DLR' | '3DTB' | '3DBT' | 'UNKNOWN',VideoSource形如{fileFormat?, url}。

3.2 生命周期与底层调用链

  • constructor:this._player = VideoModule.createPlayer(),创建专属播放器实例(不占用默认播放器);
  • componentDidMount:通过findNodeHandle(this)+UIManager.getViewRootID查询自身所属 Surface,随后_updateVideo(this.props)发起播放,再回调onPlayerCreated把播放器实例交给外部,最后_fadeVideoControl()启动控制条自动淡出计时(3 秒,见常量VIDEO_CONTROL_FADE_DURATION = 3000);
  • source 变更:_updateVideo先用sourceEqual深度比较新旧 source(支持数组形式多格式候选源),source 变化则调用player.play({source, layout, muted, stereo, volume}),否则仅player.setParams({muted, volume})增量更新,避免重复加载;
  • 渲染:每次render都通过UIManager.measureInWindow重新测量视图在窗口中的矩形坐标(onLayout触发),再调用Environment.setScreen(screenId, player._player, surface, x, y, width, height)把视频纹理贴到该矩形区域——因此视频画面与占位 View 严格重合;visible=false时传入null播放器以摘除纹理;
  • 卸载:先Environment.setScreen(screenId, null, surface, 0, 0, 1, 1)摘除画面,再this._player.destroy()销毁播放器并清理淡出计时器。

3.3 控制条自动淡出交互

VideoPlayer外层是一个VrButton:指针进入或点击(onEnter/onClick)时_showVideoControl让控制条显形并重新计时;指针离开(onExit)时_fadeVideoControl在 3 秒后把控制条opacity降为 0。同时控制条自身也把进入/离开状态上报给父级:当用户指针停留在控制条上(isControlFocused)时暂停淡出计时,避免正在操作时控制条消失(见 VideoPlayer.react.js)。控制条默认占容器高度 10%、宽度 100%,可通过controlStyle覆盖。

四、快速上手:在自己的项目中集成

在package.json中加入依赖后(或直接以源码方式引入):

import {VideoPlayer, VideoControl} from 'react-360-common-ui';

最简用法——2D 视频 + 内嵌控制条:

<VideoPlayer style={{width: 4, height: 2.25}} source={{url: asset('my-video.webm').uri}} volume={1.0} muted={false} showControl={true} onPlayerCreated={player => console.log('player ready', player)} />

将VideoControl单独用于 360 背景视频:因为背景视频不参与 Surface 布局,控制条可以独立摆放在场景任意位置,只需传入同一个播放器实例即可共享状态:

import VideoModule from 'VideoModule'; import {Environment} from 'react-360'; const player = VideoModule.createPlayer(); player.play({ source: {url: asset('video360.mp4').uri}, layout: 'SPHERICAL', autoPlay: true, }); Environment.setBackgroundVideo(player._player); // 场景中任意位置的浮动控制条 <VideoControl player={player} fontSize={20} style={{width: 6, height: 0.5}} />

关于VideoModule播放器上限:源码 Libraries/VRModules/VideoModule.js 显示createPlayer会受原生maxPlayers限制(默认 1,-1 表示不限制),且同名播放器不允许重复创建,因此多个视频并存时建议显式传入不同name。

五、进阶参考:MediaAppTemplate 示例中的工程化用法

官方示例 Samples/MediaAppTemplate/index.js 展示了比组件库更进一步的生产级模式:用两组视频播放器交替实现“预加载 + 无缝切换”:

  • 预加载:_preloadVideo对未挂载到环境的播放器调用player.play({source, muted: true, autoPlay: false}),并监听onVideoStatusChanged直到status === 'ready'再 resolve(见 MediaAppTemplateScenePage.react.js);
  • 切换:loadScene中停掉旧播放器、交换两组播放器引用,再调用resume()继续播放已缓冲的视频,同时用Environment.setBackgroundImage/Environment.setBackgroundVideo切换全景内容;
  • 贴屏:MediaAppTemplateVideoScreen通过UIManager.measureInWindow获取占位 View 坐标后调用Environment.setScreen把 2D 视频贴到 Surface 指定区域(见 MediaAppTemplateVideoScreen.react.js)。

该示例也印证了Environment.setScreen的语义:屏幕总是渲染在 Surface 所有 React 组件之后,可作为承载视频画面的“背景层”。

六、与 MediaPlayerState 的关系

需要说明的是,react-360-common-ui中的VideoPlayer/VideoControl直接面向VideoModule播放器实例;而库内另有一个基于MediaPlayerState的VideoControl变体用于与原生<Video>组件联动(见 Libraries/Video/MediaPlayerState.js 的使用说明)。两者的选择标准很简单:需要 360 背景/贴屏视频时用VideoModule+ 本组件库;需要普通场景内嵌 2D 视频时用<Video>+MediaPlayerState。

七、小结

react-360-common-ui的价值在于把 React 360 视频播放中最繁琐的样板代码(创建播放器、测量坐标、贴屏、状态同步、凝视交互)封装成声明式组件,同时保持对底层VideoModule的完全透传。核心要点:

  • VideoControl面向VideoPlayerInstance,提供播放/暂停、静音、音量、进度跳转与自动时间格式化;
  • VideoPlayer封装“建播放器 → 测量 →Environment.setScreen贴屏”链路,并内置 3 秒自动淡出控制条;
  • 两者均不依赖外部图片资源,图标由createGlyph矢量指令即时生成。

源码入口:组件实现见 addons/react-360-common-ui/src/VideoPlayer.react.js 与 addons/react-360-common-ui/src/VideoControl.react.js,底层播放器 API 见 Libraries/VRModules/VideoModule.js,完整示例见 Samples/MediaAppTemplate/index.js 与 docs/example-mediaapptemplate.md。

  • 前端
  • 3D渲染

【免费下载链接】react-360

Create amazing 360 and VR content using React

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

相关推荐

上一篇:ComfyUI ControlNet Aux模型下载失败:从诊断到修复的完整技术指南
下一篇:ComfyUI ControlNet Aux:探索AI图像预处理的无限可能

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

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

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

立即咨询