HarmonyOS NEXT 视频播放器开发:Video 组件、进度控制与全屏切换实战
HarmonyOS NEXT 视频播放器开发:Video 组件、进度控制与全屏切换实战
前言
视频播放是文件管理与工具箱应用中的高频功能,HarmonyOS NEXT 提供了强大的 Video 组件和 Media Kit 能力。本文基于 HarmonyExplorer 项目,详细讲解视频播放器(Video Player)页面的完整开发流程,包括 Video 组件使用、播放暂停控制、进度条拖拽、快进快退、倍速播放、全屏切换、VideoItem 组件封装和播放器状态管理。
一、视频播放器架构设计
1.1 整体架构概述
视频播放器采用 分层架构 设计,ViewModel 负责管理播放状态,Service 处理业务逻辑,KitManager 封装 Media Kit 底层能力。
enum PlayState {
Idle = 0, Playing = 1, Paused = 2, Stopped = 3, Error = 4
}
@Observed
class VideoPlayerViewModel {
public playState: PlayState = PlayState.Idle;
public currentTime: number = 0;
public duration: number = 0;
public playbackSpeed: number = 1.0;
public isFullScreen: boolean = false;
public videoList: Array<FileInfo> = [];
public currentIndex: number = 0;
}
1.2 状态管理策略
播放器通过 PlayState 枚举明确区分各种状态,状态驱动 的设计方式使 UI 响应更加精准。
提示:在设计播放器状态时,应使用枚举类型而非布尔值组合,这样可以有效避免状态冲突。
二、Video 组件基础使用
2.1 Video 组件配置
Video 组件支持本地视频和网络视频播放,内置播放控制栏,也支持自定义控制界面。
Video({
src: this.viewModel.currentVideoPath,
currentProgressRate: this.viewModel.playbackSpeed
})
.width('100%')
.height(this.viewModel.isFullScreen ? '100%' : 240)
.controls(false)
.autoPlay(true)
.onStart(() => { this.viewModel.playState = PlayState.Playing; })
.onPause(() => { this.viewModel.playState = PlayState.Paused; })
.onFinish(() => { this.playNext(); })
.onTimeUpdate((event: TimeEvent) => {
this.viewModel.currentTime = event.currentTime;
})
.onPrepared((event: PreparedEvent) => {
this.viewModel.duration = event.duration;
})
2.2 Video 组件属性说明
| 属性名 | 类型 | 说明 | 默认值 |
|---|---|---|---|
| src | string | 视频源路径 | - |
| controls | boolean | 显示控制栏 | true |
| autoPlay | boolean | 自动播放 | false |
| muted | boolean | 静音 | false |
| loop | boolean | 循环播放 | false |
三、播放与暂停控制
3.1 播放控制实现
播放与暂停通过 VideoController 控制,同时更新 ViewModel 中的播放状态。
@Component
struct VideoPlayerPage {
@State viewModel: VideoPlayerViewModel = new VideoPlayerViewModel();
private videoController: VideoController = new VideoController();
private togglePlayPause(): void {
if (this.viewModel.playState === PlayState.Playing) {
this.videoController.pause();
this.viewModel.playState = PlayState.Paused;
} else {
this.videoController.start();
this.viewModel.playState = PlayState.Playing;
}
}
@Builder
buildPlayButton(): void {
Image(this.viewModel.playState === PlayState.Playing
? 'resources/pause_icon.png' : 'resources/play_icon.png')
.width(48).height(48)
.onClick(() => { this.togglePlayPause(); })
}
}
3.2 播放状态同步
播放状态需要在 UI 和 ViewModel 之间保持同步,通过 Video 组件的生命周期回调自动更新。
- 播放器初始化时注册 onStart、onPause、onFinish 回调
- 回调触发时更新 ViewModel 中的 PlayState 枚举值
- UI 层通过 @Observed 监听状态变化自动刷新控制按钮
- 异常情况通过 onError 回调捕获并显示错误提示
四、进度条拖拽实现
4.1 自定义进度条
自定义进度条支持拖拽跳转和实时进度显示,通过 Slider 组件实现。
Row() {
Text(this.formatTime(this.viewModel.currentTime)).fontSize(12).fontColor('#FFFFFF')
Slider({
value: this.viewModel.currentTime,
min: 0,
max: this.viewModel.duration,
step: 1,
style: SliderStyle.OutSet
})
.layoutWeight(1)
.selectedColor('#007DFF')
.onChange((value: number, mode: SliderChangeMode) => {
if (mode === SliderChangeMode.End || mode === SliderChangeMode.Click) {
this.videoController.setCurrentTime(value);
this.viewModel.currentTime = value;
}
})
Text(this.formatTime(this.viewModel.duration)).fontSize(12).fontColor('#FFFFFF')
}
.width('100%').padding({ left: 16, right: 16 })
4.2 拖拽逻辑处理
| 拖拽阶段 | 触发条件 | 处理逻辑 | UI 反馈 |
|---|---|---|---|
| 开始 | 手指按下 | 记录位置 | 高亮进度条 |
| 进行中 | 手指移动 | 实时预览 | 更新气泡 |
| 结束 | 手指抬起 | 跳转位置 | 恢复状态 |
五、快进与快退功能
5.1 快进快退实现
快进快退通过 setCurrentTime 方法实现,每次调整固定时间间隔。
class VideoControlService {
private static readonly SEEK_INTERVAL: number = 10;
public static fastForward(
controller: VideoController,
viewModel: VideoPlayerViewModel
): void {
const target: number = Math.min(
viewModel.currentTime + VideoControlService.SEEK_INTERVAL,
viewModel.duration
);
controller.setCurrentTime(target);
viewModel.currentTime = target;
}
public static rewind(
controller: VideoController,
viewModel: VideoPlayerViewModel
): void {
const target: number = Math.max(
viewModel.currentTime - VideoControlService.SEEK_INTERVAL, 0
);
controller.setCurrentTime(target);
viewModel.currentTime = target;
}
}
5.2 手势快进快退
除按钮控制外,还可通过水平滑动手势实现快进快退,提供更自然的交互方式。
提示:手势快进快退时,建议在屏幕上显示进度预览气泡,让用户直观感知快进快退的幅度。
六、倍速播放实现
6.1 倍速控制
倍速播放通过 currentProgressRate 属性实现,支持常见倍速档位。
@Builder
buildSpeedSelector(): void {
Column() {
ForEach([0.75, 1.0, 1.25, 1.5, 2.0], (speed: number) => {
Text(speed === 1.0 ? '正常' : speed + 'x')
.fontSize(14)
.fontColor(this.viewModel.playbackSpeed === speed ? '#007DFF' : '#333333')
.padding({ top: 8, bottom: 8 })
.width(80)
.textAlign(TextAlign.Center)
.onClick(() => { this.viewModel.playbackSpeed = speed; })
})
}
.backgroundColor('#FFFFFF').borderRadius(8)
}
6.2 倍速档位说明
- 0.75x:适合学习外语视频,慢速理解内容
- 1.0x:正常播放速度,适合大多数场景
- 1.5x:中速加速,适合知识类视频
- 2.0x:高速播放,适合快速回顾内容
七、全屏切换实现
7.1 全屏模式切换
全屏切换需要调整 Video 组件尺寸和页面布局,同时处理横竖屏切换。
private toggleFullScreen(): void {
this.viewModel.isFullScreen = !this.viewModel.isFullScreen;
window.getLastWindow(getContext(this)).then((win: window.Window) => {
if (this.viewModel.isFullScreen) {
win.setPreferredOrientation(window.Orientation.LANDSCAPE);
} else {
win.setPreferredOrientation(window.Orientation.PORTRAIT);
}
});
}
7.2 全屏适配处理
| 适配项 | 竖屏模式 | 全屏模式 | 处理方式 |
|---|---|---|---|
| 方向 | 竖屏 | 横屏 | setPreferredOrientation |
| 状态栏 | 显示 | 隐藏 | setWindowSystemBarEnable |
| 控制栏 | 底部 | 浮层 | Stack 层叠 |
| 返回键 | 导航栏 | 浮层按钮 | 自定义按钮 |
八、VideoItem 组件封装
8.1 VideoItem 组件设计
VideoItem 是视频列表中的单项展示组件,显示视频缩略图、名称和时长。
@Component
struct VideoItem {
@Prop fileInfo: FileInfo;
@Prop duration: number;
public onItemClick: (fileInfo: FileInfo) => void = () => {};
build(): void {
Row() {
Stack() {
Image(this.fileInfo.path)
.width(120).height(80).borderRadius(8).objectFit(ImageFit.Cover)
Image('resources/play_overlay.png').width(32).height(32)
}.width(120).height(80)
Column() {
Text(this.fileInfo.name).fontSize(14).maxLines(2)
.textOverflow({ overflow: TextOverflow.Ellipsis })
Text(VideoControlService.formatTime(this.duration))
.fontSize(12).fontColor('#999999').margin({ top: 4 })
}.layoutWeight(1).margin({ left: 12 }).alignItems(HorizontalAlign.Start)
}.width('100%').padding(12)
.onClick(() => { this.onItemClick(this.fileInfo); })
}
}

视频播放器页面效果展示,支持播放控制和全屏切换
8.2 组件复用策略
VideoItem 通过 @Prop 接收数据,回调函数处理点击事件。组件复用 可以显著提升列表滚动性能。
九、Media Kit 视频信息获取
9.1 视频元数据读取
Media Kit 提供 videoMetadata 接口,可以获取视频的时长、分辨率、编码格式等信息。
import { media } from '@kit.MediaKit';
class VideoMetadataService {
public static async getVideoMetadata(filePath: string): Promise<VideoMetadata> {
const fileFd: number = await FileUtil.openFile(filePath);
const metadata: media.VideoMetadata = await media.getVideoMetadata(fileFd);
const result: VideoMetadata = {
duration: metadata.duration,
width: metadata.width,
height: metadata.height,
codec: metadata.codec
};
await FileUtil.closeFile(fileFd);
return result;
}
}
interface VideoMetadata {
duration: number;
width: number;
height: number;
codec: string;
}
9.2 缩略图生成
视频缩略图通过 createThumbnail 接口生成,缓存在本地避免重复生成。
提示:视频缩略图生成是耗时操作,应在后台线程执行,同时建立本地缓存机制。
十、播放器状态管理
10.1 完整 ViewModel 实现
播放器 ViewModel 统一管理所有播放状态和业务逻辑,是视频播放器的核心控制器。
@Observed
class VideoPlayerViewModel {
public playState: PlayState = PlayState.Idle;
public currentTime: number = 0;
public duration: number = 0;
public playbackSpeed: number = 1.0;
public isFullScreen: boolean = false;
public videoList: Array<FileInfo> = [];
public currentIndex: number = 0;
public currentVideoPath: string = '';
private repository: FileRepository = new FileRepository();
public get currentVideo(): FileInfo {
if (this.videoList.length === 0) { return new FileInfo(); }
return this.videoList[this.currentIndex];
}
public async loadVideoList(dirPath: string): Promise<void> {
const files: Array<FileInfo> = await this.repository.getVideosByPath(dirPath);
this.videoList = files;
if (files.length > 0) {
this.currentIndex = 0;
this.currentVideoPath = files[0].path;
}
}
public playNext(): void {
if (this.videoList.length === 0) { return; }
this.currentIndex = (this.currentIndex + 1) % this.videoList.length;
this.currentVideoPath = this.currentVideo.path;
this.currentTime = 0;
this.playState = PlayState.Playing;
}
public reset(): void {
this.currentTime = 0;
this.playState = PlayState.Idle;
this.playbackSpeed = 1.0;
}
}
10.2 状态流转设计
播放器状态流转需要遵循明确的生命周期,状态机模式 是管理复杂播放状态的有效手段。
十一、控制层 UI 实现
11.1 控制层布局
控制层通过 Stack 层叠在 Video 组件上方,包含播放按钮、进度条、倍速选择和全屏按钮。
@Builder
buildControlLayer(): void {
Column() {
Row() {
Image('resources/back_icon.png').width(24).height(24)
.onClick(() => {
if (this.viewModel.isFullScreen) { this.toggleFullScreen(); }
else { RouterUtil.back(); }
})
Text(this.viewModel.currentVideo.name).fontSize(16)
.fontColor('#FFFFFF').layoutWeight(1).margin({ left: 8 })
Image('resources/fullscreen_icon.png').width(24).height(24)
.onClick(() => { this.toggleFullScreen(); })
}.width('100%').height(48).padding({ left: 16, right: 16 })
Blank()
Row() {
this.buildPlayButton()
Image('resources/previous_icon.png').width(32).height(32)
.onClick(() => this.viewModel.playPrevious())
Image('resources/next_icon.png').width(32).height(32)
.onClick(() => this.viewModel.playNext())
this.buildSpeedSelector()
}.width('100%').height(56).justifyContent(FlexAlign.SpaceEvenly)
.backgroundColor('#80000000')
}.width('100%').height('100%').justifyContent(FlexAlign.SpaceBetween)
}
11.2 控制层显隐
控制层默认显示,播放时自动隐藏,点击屏幕切换显隐状态,提供沉浸式观看体验。
十二、性能优化与最佳实践
12.1 内存管理
视频播放是内存密集型操作,合理的内存管理可以避免 OOM 崩溃。
- 列表项不可见时释放缩略图资源
- 切换视频时释放上一个 VideoController
- 限制同时加载的视频缩略图数量
- 使用缓存池管理缩略图资源
12.2 播放优化建议
| 优化项 | 优化方案 | 预期效果 |
|---|---|---|
| 启动速度 | 预加载视频元数据 | 减少等待时间 |
| 拖拽流畅度 | 关键帧索引 | 快速定位 |
| 缩略图加载 | 内存+磁盘双缓存 | 消除卡顿 |
| 全屏切换 | 动画过渡 | 平滑切换 |
提示:在开发视频播放器时,务必在真机上进行充分测试,模拟器可能无法准确反映视频解码性能。
总结
本文基于 HarmonyExplorer 项目完整讲解了 HarmonyOS NEXT 视频播放器的开发流程,涵盖了 Video 组件使用、播放暂停控制、进度条拖拽、快进快退、倍速播放、全屏切换、VideoItem 组件封装和 Media Kit 视频信息获取等核心功能。通过合理的状态管理和架构设计,开发者可以构建出功能完善、体验流畅的视频播放应用。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源
更多推荐

所有评论(0)