HarmonyOS7 视频播放:Video 组件从入门到自定义控制器

📅 2026/7/24 20:57:06
HarmonyOS7 视频播放:Video 组件从入门到自定义控制器
文章目录前言Video 组件基础自定义播放控制全屏切换手势控制进度性能优化写在最后前言视频播放这功能看着简单——不就是个 Video 组件嘛。但真要做得像样自定义控制器、全屏切换、手势控进度一个比一个折腾。HarmonyOS7 自带的 Video 组件默认控制器功能有限样式也不可控。想要自己的播放器 UI就得手动搞一套。这篇文章从最基础的用法讲起一路到自定义控制器 手势控制够你做出一个像样的视频播放器。我的目标是看完这篇你能做出一个带自定义进度条、播放/暂停按钮、全屏切换、手势拖动进度的视频播放器。HarmonyOS7 的 Video 组件本身能力是够的关键在于怎么把默认控制器关掉自己接管所有交互逻辑。Video 组件基础最简单的用法三行代码就能播放视频StatevideoSrc:Resource$rawfile(demo.mp4);controller:VideoControllernewVideoController();Video({src:this.videoSrc,controller:this.controller}).width(100%).height(300)支持的视频源类型类型示例本地 rawfile$rawfile(video.mp4)网络地址https://example.com/video.mp4沙箱 URIfile:///data/storage/.../video.mp4用网络地址需要在module.json5里申请ohos.permission.INTERNET权限。Video 组件的常用属性Video({src:this.videoSrc,controller:this.controller}).autoPlay(false).loop(false).controls(true).objectFit(ImageFit.Contain).onStart((){console.info(开始播放);}).onPause((){console.info(暂停);}).onFinish((){console.info(播放结束);}).onPrepared((e){if(e)console.info(视频时长:${e.duration}秒);}).onUpdate((e){if(e)console.info(当前进度:${e.time}秒);}).onFullscreenChange((e){if(e)console.info(全屏状态:${e.fullscreen});})属性讲解autoPlay— 是否自动播放默认 falseloop— 是否循环播放controls—是否显示默认控制器自定义控制器时要设为 falseobjectFit— 视频填充模式Contain保持比例不裁剪onPrepared— 视频加载完成e.duration是总时长onUpdate— 播放进度回调e.time是当前秒数自定义播放控制默认控制器关掉后controls(false)所有交互都得自己实现。先看完整代码Componentexportstruct CustomVideoPlayer{StatevideoSrc:Resource$rawfile(demo.mp4);StateisPlaying:booleanfalse;StatecurrentTime:number0;Stateduration:number0;StateshowControls:booleantrue;controller:VideoControllernewVideoController();build(){Stack({alignContent:Alignment.Bottom}){Video({src:this.videoSrc,controller:this.controller}).width(100%).height(300).controls(false).autoPlay(false).onPrepared((e){if(e)this.duratione.duration;}).onUpdate((e){if(e)this.currentTimee.time;}).onFinish((){this.isPlayingfalse;}).onClick((){this.showControls!this.showControls;})if(this.showControls){Column(){Slider({value:this.currentTime,min:0,max:this.duration,step:1}).width(90%).onChange((value){this.controller.setCurrentTime(value);})Row({space:20}){Button(this.isPlaying?暂停:播放).onClick((){if(this.isPlaying){this.controller.pause();}else{this.controller.start();}this.isPlaying!this.isPlaying;})Text(${this.formatTime(this.currentTime)}/${this.formatTime(this.duration)}).fontColor(Color.White).fontSize(12)}.width(90%).justifyContent(FlexAlign.Center)}.width(100%).padding(10).backgroundColor(#88000000)}}}formatTime(seconds:number):string{letminMath.floor(seconds/60);letsecMath.floor(seconds%60);return${min.toString().padStart(2,0)}:${sec.toString().padStart(2,0)};}}逐行讲解自定义控制器核心逻辑controls(false)— 关掉默认控制器这是自定义的前提onClick切换showControls— 点击视频区域显示/隐藏控制栏Slider组件绑定currentTime和duration— 进度条跟随播放进度实时更新onChange里调用controller.setCurrentTime(value)— 用户拖动进度条时跳转播放位置播放/暂停按钮通过controller.start()/controller.pause()控制formatTime把秒数格式化成mm:ss格式关键点isPlaying状态要自己维护。onFinish时别忘了置为 false不然按钮显示会错。全屏切换全屏切换用controller.requestFullscreen()方法StateisFullscreen:booleanfalse;Button(this.isFullscreen?退出全屏:全屏).onClick((){if(this.isFullscreen){this.controller.exitFullscreen();}else{this.controller.requestFullscreen(true);}})// 监听全屏状态变化.onFullscreenChange((e){if(e)this.isFullscreene.fullscreen;})讲解requestFullscreen(true)— 参数 true 表示横屏全屏false 为竖屏exitFullscreen()— 退出全屏必须监听onFullscreenChange来同步状态因为用户也可能通过系统手势退出全屏全屏时视频容器的尺寸也要跟着变Video({src:this.videoSrc,controller:this.controller}).width(this.isFullscreen?100%:100%).height(this.isFullscreen?100%:300)小坑全屏状态下自定义控制栏的布局可能需要调整。建议全屏时把控制栏放在底部加个半透明背景。手势控制进度拖动手势调进度这是短视频 App 的标配功能。用PanGesture实现StatepanStartTime:number0;StatepanDeltaX:number0;Video({src:this.videoSrc,controller:this.controller}).controls(false).gesture(PanGesture({fingers:1,direction:PanDirection.HORIZONTAL}).onActionStart((){this.panStartTimethis.currentTime;this.showControlsfalse;}).onActionUpdate((e){// 水平滑动距离转换为时间偏移lettotalWidth300;// 视频容器宽度letdeltaSeconds(e.offsetX/totalWidth)*this.duration;lettargetTimeMath.max(0,Math.min(this.duration,this.panStartTimedeltaSeconds));this.currentTimetargetTime;}).onActionEnd((){this.controller.setCurrentTime(this.currentTime);this.showControlstrue;}))逐行讲解PanDirection.HORIZONTAL— 只响应水平方向的手势onActionStart记录拖动开始时的播放时间onActionUpdate根据手指水平偏移量计算新的播放位置。偏移量 / 容器宽度 × 总时长 时间偏移onActionEnd手指抬起后调用setCurrentTime跳到目标位置Math.max(0, Math.min(this.duration, ...))防止进度超出范围性能优化视频播放是吃资源的大户几个优化建议及时释放控制器页面销毁时调用controller.stop()释放资源预加载封面图用previewUri设置视频封面避免黑屏等待Video({src:this.videoSrc,controller:this.controller,previewUri:$rawfile(cover.jpg)})按需加载只有视频进入可视区域时才初始化播放器避免同时播放多个视频同时解码多个视频流非常吃内存网络视频用 HLS 协议支持分段加载起播更快写在最后自定义视频播放器确实比直接用默认控制器费劲不少但好处是 UI 完全可控交互想怎么设计都行。我建议先从基础用法入手跑通了再一步步加自定义控制、全屏、手势。一口吃不成胖子但一步步来最后的效果肯定比默认的好看。