OpenHarmony实战开发-使用ArkTS语言实现简易视频播放器

介绍

本篇Codelab使用ArkTS语言实现视频播放器,主要包括主界面和视频播放界面,我们将一起完成以下功能:

  1. 主界面顶部使用Swiper组件实现视频海报轮播。
  2. 主界面下方使用List组件实现视频列表。
  3. 播放界面使用Video组件实现视频播放。
  4. 在不使用视频组件默认控制器的前提下,实现自定义控制器。
  5. 播放界面底部使用图标控制视频播放/暂停。
  6. 播放界面底部使用Slider组件控制和实现视频播放进度。
  7. 播放界面使用Stack容器组件的Z序控制实现在视频播放画面上添加开始/暂停/加载图标。

相关概念

  • Swiper组件:滑动容器,提供切换子组件显示的能力。
  • List组件:列表包含一系列相同宽度的列表项。适合连续、多行呈现同类数据,例如图片和文本。
  • Video组件:用于播放视频文件并控制其播放状态的组件。
  • Navigator组件:路由容器组件,提供路由跳转能力。
  • ForEach组件:基于数组类型数据执行循环渲染。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

├──entry/src/main/ets             // 代码区
│  ├──common
│  │  └──constants
│  │     └──CommonConstants.ets   // 样式常量类
│  ├──entryability
│  │  └──EntryAbility.ts          // 程序入口类
│  ├──model
│  │  └──VideoControll.ets        // 视频播放控制相关方法类
│  ├──pages
│  │  ├──SimpleVideoIndex.ets     // 主界面
│  │  └──SimpleVideoPlay.ets      // 视频播放界面
│  ├──view
│  │  ├──IndexModule.ets          // 自定义首页List模块组件文件
│  │  ├──IndexSwiper.ets          // 自定义首页Swiper组件文件
│  │  ├──VideoPlayer.ets          // 自定义播放界面视频组件文件
│  │  └──VideoPlaySlider.ets      // 自定义播放界面视频进度条组件文件
│  └──viewmodel
│     ├──HorizontalVideoItem.ets  // 水平视频类
│     ├──ParamItem.ets            // 参数类
│     ├──SwiperVideoItem.ets      // 自定义播放界面视频组件文件
│     └──VideoData.ets            // 首页相关数据
└──entry/src/main/resource        // 应用静态资源目录

构建主界面

主界面由视频轮播模块和多个视频列表模块组成,效果如图所示:

VideoData.ets中定义的视频轮播图数组SWIPER_VIDEOS和视频列表图片数组HORIZONTAL_VIDEOS。

// VideoData.ets
import { HorizontalVideoItem } from './HorizontalVideoItem';
import { SwiperVideoItem } from './SwiperVideoItem';export const SWIPER_VIDEOS: SwiperVideoItem[] = [new SwiperVideoItem($r('app.media.ic_banner1')),new SwiperVideoItem($r('app.media.ic_banner2')),new SwiperVideoItem($r('app.media.ic_banner3'))
];export const HORIZONTAL_VIDEOS: HorizontalVideoItem[] = [new HorizontalVideoItem(1, $r('app.media.ic_video_list0'), '视频1'),new HorizontalVideoItem(2, $r('app.media.ic_video_list1'), '视频2'),new HorizontalVideoItem(3, $r('app.media.ic_video_list2'), '视频3')
];

IndexSwiper.ets文件中定义的轮播图子组件SwiperVideo,点击轮播图片,页面跳转到视频播放页面,并携带本地视频flag,效果如图所示:

// IndexSwiper.ets
@Component
export struct SwiperVideo {build() {Column() {Swiper() {ForEach(SWIPER_VIDEOS, (item: SwiperVideoItem) => {SwiperItem({ imageSrc: item.image, source: $rawfile('videoTest.mp4') })}, (item: SwiperVideoItem) => JSON.stringify(item))}.autoPlay(true)}// 样式设置...}
}@Component
struct SwiperItem {private imageSrc: Resource = $r('app.string.empty');private source: Resource = $r('app.string.empty');private paramItem: ParamItem = new ParamItem();...build() {// 跳转一:使用Navigator组件跳转到视频播放界面Navigator({ target: SECOND_PAGE, type: NavigationType.Push }) {Image(this.imageSrc).borderRadius(MARGIN_FONT_SIZE.FIRST_MARGIN)}.params(this.paramItem)}
}

IndexModule.ets文件中定义的视频列表图片子组件VideoModule,点击子组件中的图片,页面跳转到视频播放页面,并携带网络视频flag,效果如图所示:

// IndexModule.ets
@Component
export struct VideoModule {private moduleName: string = '';build() {Column() {// 视频列表上方的文本信息...// 视频列表组件List({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) {ForEach(HORIZONTAL_VIDEOS, (item: HorizontalVideoItem) => {ListItem() {HorizontalItem({imageSrc: item.image,source: NET,videoName: item.name})}}, (item: HorizontalVideoItem) => JSON.stringify(item))}// 设置列表横向排列.listDirection(Axis.Horizontal)}// 样式设置...}
}@Component
struct HorizontalItem {private imageSrc: Resource = $r('app.string.empty');private source: string = '';private videoName: string = '';build() {// 跳转二:使用route跳转到视频播放界面Column() {Image(this.imageSrc).width(MARGIN_FONT_SIZE.SEVENTH_MARGIN).height(MARGIN_FONT_SIZE.SIXTH_MARGIN).onClick(() => {router.pushUrl({url: SECOND_PAGE,params: { source: this.source }});})...}.justifyContent(FlexAlign.Center)}
}

在SimpleVideoIndex.ets主界面中引用SwiperVideo和VideoModule子组件。

// SimpleVideoIndex.ets
@Entry
@Component
struct SimpleVideoIndex {build() {Column({ space: MARGIN_FONT_SIZE.FOURTH_MARGIN }) {// 视频轮播组件SwiperVideo()List() {ForEach(LIST, (item: string) => {ListItem() {VideoModule({ moduleName: item }).margin({ top: MARGIN_FONT_SIZE.FIRST_MARGIN })}}, (item: string) => JSON.stringify(item))}.listDirection(Axis.Vertical).margin({ top: MARGIN_FONT_SIZE.THIRD_MARGIN })}...}
}

构建视频播放界面

VideoPlayer.ets其中定义了视频播放子组件VideoPlayer ,onPrepared回调方法中可以获取视频总时长,onUpdate回调方法中可实时获取到视频播放的当前时间戳,onFinish是视频播放结束后的回调方法,onError是视频播放出错的回调方法。

// VideoPlayer.ets
@Component
export struct VideoPlayer {private source: string | Resource = '';private controller: VideoController = new VideoController();private previewUris: Resource = $r('app.media.preview');@Provide currentTime: number = 0;@Provide durationTime: number = 0;@Provide durationStringTime: string = START_TIME;@Provide currentStringTime: string = START_TIME;@Consume isPlay: boolean;@Consume isOpacity: boolean;@Consume flag: boolean;@Consume isLoading: boolean;@Consume progressVal: number;build() {Column() {Video({src: this.source,previewUri: this.previewUris,controller: this.controller}).width(ALL_PERCENT).height(STRING_PERCENT.NINETY_PERCENT).controls(false).autoPlay(false).objectFit(ImageFit.Contain).loop(false).onUpdate((event) => {if (event) {this.currentTime = event.time;this.currentStringTime = changeSliderTime(this.currentTime);}}).onPrepared((event) => {this.prepared(event?.duration);}).onFinish(() => {this.finish();}).onError(() => {prompt.showToast({duration: COMMON_NUM_DURATION,message: MESSAGE});})VideoSlider({ controller: this.controller })}}...
}

在自定义组件VideoPlayer底部使用了自定义子组件VideoSlider,VideoSlider自定义组件中显示和控制视频播放进度,效果如图所示:

// VideoPlaySlider.ets
@Component
export struct VideoSlider {@Consume isOpacity: boolean;private controller: VideoController = new VideoController();@Consume currentStringTime: string;@Consume currentTime: number;@Consume durationTime: number;@Consume durationStringTime: string;@Consume isPlay: boolean;@Consume flag: boolean;@Consume isLoading: boolean;@Consume progressVal: number;build() {Row({ space: MARGIN_FONT_SIZE.FIRST_MARGIN }) {...Slider({value: this.currentTime,min: 0,max: this.durationTime,step: 1,style: SliderStyle.OutSet}).blockColor($r('app.color.white')).width(STRING_PERCENT.SLIDER_WITH).trackColor(Color.Gray).selectedColor($r("app.color.white")).showSteps(true).showTips(true).trackThickness(this.isOpacity ? SMALL_TRACK_THICK_NESS : BIG_TRACK_THICK_NESS).onChange((value: number, mode: SliderChangeMode) => {this.sliderOnchange(value, mode);})...}.opacity(this.isOpacity ? DEFAULT_OPACITY : 1)...}...
}

在VideoController.ets中的视频控制和回调的相关方法。

// VideoControll.ets
export function changeSliderTime(value: number): string {let second: number = value % COMMON_NUM_MINUTE;let min: number = Number.parseInt((value / COMMON_NUM_MINUTE).toString());let head = min < COMMON_NUM_DOUBLE ? `${ZERO_STR}${min}` : min;let end = second < COMMON_NUM_DOUBLE ? `${ZERO_STR}${second}` : second;let nowTime = `${head}${SPLIT}${end}`;return nowTime;
}


在SimpleVideoPlay.ets播放界面,引用VideoPlayer子组件,并在视频播放页面使用堆叠容器,在视频播放画面中心堆叠控制、视频加载图标,效果如图所示:

// SimpleVideoPlay.ets
@Entry
@Component
struct Play {// 取到Index页面跳转来时携带的source对应的数据。private source: string = (router.getParams() as Record<string, Object>).source as string;private startIconResource: Resource = $r('app.media.ic_public_play');private backIconResource: Resource = $r('app.media.ic_back');@Provide isPlay: boolean = false;@Provide isOpacity: boolean = false;controller: VideoController = new VideoController();@Provide isLoading: boolean = false;@Provide progressVal: number = 0;@Provide flag: boolean = false;...onPageHide() {this.controller.pause();}build() {Column() {// 顶部返回以及标题...Stack() {// 不同的播放状态渲染不同得控制图片if (!this.isPlay && !this.isLoading) {Image(this.startIconResource).width(MARGIN_FONT_SIZE.FIFTH_MARGIN).height(MARGIN_FONT_SIZE.FIFTH_MARGIN)// 同一容器中兄弟组件显示层级关系,z值越大,显示层级越高 用于控制图片在视频上。.zIndex(STACK_STYLE.IMAGE_Z_INDEX)}if (this.isLoading) {Progress({value: STACK_STYLE.PROGRESS_VALUE,total: STACK_STYLE.PROGRESS_TOTAL,type: ProgressType.ScaleRing}).color(Color.Grey).value(this.progressVal).width(STACK_STYLE.PROGRESS_WIDTH).style({strokeWidth: STACK_STYLE.PROGRESS_STROKE_WIDTH,scaleCount: STACK_STYLE.PROGRESS_SCALE_COUNT,scaleWidth: STACK_STYLE.PROGRESS_SCALE_WIDTH}).zIndex(STACK_STYLE.PROGRESS_Z_INDEX)}VideoPlayer({source: this.source,controller: this.controller}).zIndex(0)}}.height(ALL_PERCENT).backgroundColor(Color.Black)}
}

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. Swiper组件的使用。
  2. List组件的使用。
  3. Video组件的使用。
  4. Slider组件的使用。
  5. 如何实现自定义视频控制器。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. ……

二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全
  5. ........

三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. ……

四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. ……

五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ……

更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/777879.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

广场舞团系统的设计与实现|Springboot+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目持续更新中..... 2024年计算机毕业论文&#xff08;设计&#xff09;学生选题参考合集推荐收藏&#xff08;包含Springboot、jsp、ssmvue等技术项目合集&#xff09; 目录 1. 系…

MySQL进阶-----索引的语法与SQL性能分析

目录 前言 一、索引语法 1.SQL语法 2.案例演示 二、SQL性能分析 三、慢查询日志 1.开启日志 2.测试样例 四、profile详情 1.开启profile 2.profile测试SQL语句 五、explain详情 1.语法结构 2.执行顺序示例&#xff08;id&#xff09; 3.执行性能示例(type) 前言 本…

记录pycharm配置Anaconda环境时没有反应的问题

记录pycharm配置Anaconda环境时没有反应的问题 背景 下载最新pycharm后在设置中配置add interpreter Anaconda环境时&#xff0c;x选中conda.ba文件点击Load Enviroments后&#xff0c;没有反应&#xff0c;就闪了一下&#xff0c;也有添加成功 探索路程 试过了重启&#x…

Vue 04 Vue 中的 Ajax、slot 插槽

Vue学习 Vue 0401 Vue中的Ajax服务器准备axios使用跨域问题解决Vue-CLI 配置代理1Vue-CLI 配置代理2案例: 用户搜索vue-resource 02 slot插槽默认插槽具名插槽作用域插槽slot总结 Vue 04 B站 Vue全家桶&#xff08;BV1Zy4y1K7SH&#xff09; 学习笔记 Vue 中的 ajax 01 Vue中的…

【动态规划】斐波那契数列模型

【动态规划】斐波那契数列模型 文章目录 【动态规划】斐波那契数列模型前言一、第 N 个泰波那契数二、三步问题三、使用最小花费爬楼梯四、解码方法总结 前言 ​ 我们将深入探讨解决斐波那契数列模型相关问题的解决方法。通过一系列精心挑选的例题&#xff0c;我们将展示如何运…

Excel:使用VLOOKUP函数,抓取指定数据,后一个列

Excel:使用VLOOKUP函数&#xff0c;抓取指定数据&#xff0c;后一个列 我们有这样一个数据源 要是实现这个页面的赋值 就是对应关系映射 使用 VLOOKUP(A2,Sheet2!$A$2:$B$9,2,FALSE)第一个参数是需要匹配的单元格。 第二个参数是数据源&#xff0c;我这里数据源用的是shee…

Unity图集编辑器

图集编辑器 欢迎使用图集编辑器新的改变编辑器图片 欢迎使用图集编辑器 Unity图集操作很是费劲 无法批量删除和添加图集中的图片 新的改变 自己写了一个图集编辑器 客&#xff1a; 支持批量删除 左键点击图片代表选中 右键点击图标定位到资产支持批量添加 选中图片拖拽到编…

python统计分析——单样本均值检验

参考资料&#xff1a;python统计分析【托马斯】 1、单样本均值的t检验 检验一个正态分布数据的均值和一个参考值的差异&#xff0c;我们一般使用单样本t检验&#xff0c;该检验基于t分布。 如果我们知道一个正态分布总体的均值和标准差&#xff0c;那么我们可以计算对应的标准…

CMOS逻辑门电路

按照制造门电路的三极管不同&#xff0c;分为MOS型、双极性和混合型。MOS型集成逻辑门有CMOS、NMOS、PMOS&#xff1b;双极型逻辑门有TTL&#xff1b;混合型有BiCMOS。 CMOS门电路是目前使用最为广泛、占主导地位的集成电路。早期CMOS电路速度慢、功耗低&#xff0c;后来随着制…

ubuntu编译OpenCV and seetaFace2

opencv opencv-4.5.2 opencv_contrib-4.5.2 SeetaFace2 SeetaFace2-master https://github.com/seetafaceengine 指定安装目录&#xff0c;和OpenCV放一个目录下了 安装前 安装 安装后 Qt安装 Windows下 Linux下 报错1 原因&#xff1a; 报错…

HTTP状态 405 - 方法不允许

方法有问题。 用Post发的请求&#xff0c;然后用Put接收的。 大家也可以看看是不是有这种问题 <body><h1>HTTP状态 405 - 方法不允许</h1><hr class"line" /><p><b>类型</b> 状态报告</p><p><b>消息…

Rust控制台输出跑马灯效果,实现刷新不换行,实现loading效果

要在 Rust 中实现控制台刷新而不换行&#xff0c;以实现类似 "loading" 状态的效果&#xff0c;你可以使用 \r&#xff08;回车符&#xff09;来覆盖上一行的内容。 use std::io::{self, Write}; use std::thread; use std::time::Duration;fn main() {let loading_…

没学数模电可以玩单片机吗?

我们首先来看一下数电模电在单片机中的应用。数电知识在单片机中主要解决各种数字信号的处理、运算&#xff0c;如数制转换、数据运算等。模电知识在单片机中主要解决各种模拟信号的处理问题&#xff0c;如采集光照强度、声音的分贝、温度等模拟信号。而数电、模电的相互转换就…

蓝桥杯_day6

文章目录 不同路径不同路径II拿金币珠宝的最高价值 不同路径 【题目描述】 一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为 “Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为…

【I.MX6ULL移植】Ubuntu-base根文件系统移植

1.下载Ubuntu16.04根文件系统 http://cdimage.ubuntu.com/ 1 2 3 4 5 2.解压ubuntu base 根文件系统 为了存放 ubuntu base 根文件系统&#xff0c;先在 PC 的 Ubuntu 系统中的 nfs 目录下创建一个名为 ubuntu_rootfs 的目录&#xff0c;命令如下&#xff1a; 【注意&…

基于单片机病房呼叫系统数码管显示房号设计

**单片机设计介绍&#xff0c;基于单片机病房呼叫系统数码管显示房号设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于单片机病房呼叫系统数码管显示房号设计概要主要涵盖了利用单片机技术实现病房呼叫系统&#xff0c;并…

WPF 多路绑定、值转换器ValueConvert、数据校验

值转换器 valueconvert 使用ValueConverter需要实现IValueConverter接口&#xff0c;其内部有两个方法&#xff0c;Convert和ConvertBack。我们在使用Binding绑定数据的时候&#xff0c;当遇到源属性和目标控件需要的类型不一致的&#xff0c;就可以使用ValueConverter&#xf…

GT收发器第一篇_总体结构介绍

文章目录 前言GT收发器介绍 前言 之前写过一篇简单介绍GT的文章https://blog.csdn.net/m0_56222647/article/details/136730026&#xff0c;可以先通过这篇文章对整体进行简单了解一下。 GT收发器介绍 参考xilinx手册ug476 对于7系列的FPGA&#xff0c;共有3个系列&#xf…

【MATLAB源码-第19期】matlab基于导频的OFDM系统瑞利信道rayleigh的信道估计仿真,输出估计与未估计误码率对比图。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 正交频分复用&#xff08;英语&#xff1a;Orthogonal frequency-division multiplexing, OFDM&#xff09;有时又称为分离复频调制技术&#xff08;英语&#xff1a;discrete multitone modulation, DMT&#xff09;&#x…

Android和IOS应用开发-Flutter应用让屏幕在 app 运行期间保持常亮的方法

文章目录 Flutter应用让屏幕在 app 运行期间保持常亮的方法方法一&#xff1a;使用系统插件方法二&#xff1a;使用 Widgets注意事项 Flutter应用让屏幕在 app 运行期间保持常亮的方法 在 Flutter 开发中&#xff0c;可以使用以下两种方法让屏幕在 app 运行期间保持常亮&#…