- 前端
- 3D渲染
【免费下载链接】react-360
Create amazing 360 and VR content using React
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() |
| 静音/取消静音 | _onMuteButtonClick | player.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
相关推荐
3步解决Mac存储焦虑:终端里的全能系统管家Mole
3步解决Mac存储焦虑:终端里的全能系统管家Mole Mac存储空间不足是许多用户面临的共同挑战。当系统运行变慢、可用空间告急时,传统清理工具往往功能单一、操作
CLI开发工具运维观测静态网站离线访问:Instatic PWA配置与测试
静态网站离线访问:Instatic PWA配置与测试 Instatic 是一款现代化的自托管可视化 CMS,支持在 1 分钟内快速部署运行。对于静态网站而言,离
CMS后端前端Mr. Data Converter高级配置指南:分隔符、空格和大小写转换的完美设置
Mr. Data Converter高级配置指南:分隔符、空格和大小写转换的完美设置 Mr. Data Converter是一款强大的开源工具,能够将Excel
前端3D渲染
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考