HarmonyOS实战开发-一次开发,多端部署-视频应用
介绍
随着智能设备类型的不断丰富,用户可以在不同的设备上享受同样的服务,但由于设备形态不尽相同,开发者往往需要针对具体设备修改或重构代码,以实现功能完整性和界面美观性的统一。OpenHarmony为开发者提供了“一次开发,多端部署”的系统能力,让开发者可以基于一次开发,快速构建不同类型终端上的应用,降低开发成本,提高开发效率。
本篇Codelab基于“一次开发,多端部署”提供的自适应布局和响应式布局能力,实现了常见的视频播放应用的主界面。通过三层工程结构尽可能复用了部分代码,并根据设备尺寸的区别设计了对应的页面以兼顾美观和易用。应用被打开时会根据具体的设备形态显示对应的UI界面,其中RK3568开发板的首页效果如图所示:
相关概念
- 一次开发,多端部署:指一套代码工程,一次开发上架,多端按需部署,目标是支撑开发者高效地开发支持多种终端设备形态的应用。
- 自适应布局:当外部容器大小发生变化时,元素可以根据相对关系自动变化以适应外部容器变化的布局能力。相对关系如占比、固定宽高比、显示优先级等。当前自适应布局能力有7种:拉伸能力、均分能力、占比能力、缩放能力、延伸能力、隐藏能力、折行能力。自适应布局能力可以实现界面显示随外部容器大小连续变化。
- 响应式布局:当外部容器大小发生变化时,元素可以根据断点、栅格或特定的特征(如屏幕方向、窗口宽高等)自动变化以适应外部容器变化的布局能力。当前响应式布局能力有3种:断点、媒体查询、栅格布局。
- GridRow:栅格容器组件,仅可以和栅格子组件(GridCol)在栅格布局场景中使用。
- GridCol:栅格子组件,必须作为栅格容器组件(GridRow)的子组件使用。
环境搭建
软件要求
- DevEco Studio版本:DevEco Studio 3.1 Release。
- OpenHarmony SDK版本:API version 9。
硬件要求
- 开发板类型:润和RK3568开发板。
- OpenHarmony系统:3.2 Release。
环境搭建
完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:
- 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:
2.搭建烧录环境。
- 完成DevEco Device Tool的安装
- 完成RK3568开发板的烧录
3.搭建开发环境。
- 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
- 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
- 工程创建完成后,选择使用真机进行调测。
代码结构解读
本篇Codelab只对核心代码进行讲解,对于完整代码,我们会在gitee中提供。
“一次开发,多端部署”推荐使用三层目录的工程结构来管理工程,上层目录包括common、features和product,common为公共特性目录,存放不同形态设备公用的类和常量,features为功能模块目录,存放应用的各个功能模块,product为产品层目录,存放不同形态设备范类代码。本Codelab不涉及功能特性,因此只存在common、product两个分层。
├──common // 公共能力层
│ ├──src/main/ets
│ │ ├──constants
│ │ │ └──CommonConstants.ets // 公共常量类
│ │ ├──utils
│ │ │ └──BreakpointSystem.ets // 断点工具类
│ │ └──viewmodel // 资源类接口
│ │ ├──BottomTabsItem.ets
│ │ ├──DriveTabsItem.ets
│ │ ├──FindTabsItem.ets
│ │ ├──HomeTabsItem.ets
│ │ └──MineTabsItem.ets
│ └──src/main/resources // 资源文件夹
└──product // 产品定制层├──default/src/main/ets // 支持手机(含折叠屏)、平板│ ├──entryability│ │ └──EntryAbility.ts // 程序入口类│ ├──pages│ │ └──MainPage.ets // 主页面│ ├──view│ │ ├──BottomTabsComponent.ets // 底部页签组件│ │ ├──DriveTabsComponent.ets // 云盘页组件│ │ ├──FindTabsComponent.ets // 发现页组件│ │ ├──HomeTabsComponent.ets // 首页组件│ │ ├──LeftTabsComponent.ets // 侧边栏组件│ │ ├──MineTabsComponent.ets // 个人页组件│ │ ├──RecentlyPlayedComponent.ets // “最近播放”列表│ │ └──RecommendComponent.ets // “为你推荐”列表│ └──viewmodel│ ├──BottomTabsModel.ets // 底部页签model│ ├──DriveTabsModel.ets // 云盘页model│ ├──FindTabsModel.ets // 发现页model│ ├──HomeTabsModel.ets // 首页model│ └──MineTabsModel.ets // 个人页model└──default/src/main/resources // 资源文件夹
主页面框架设计
为了操作便捷和充分利用不同形态设备的屏幕空间,按屏幕宽度的大小将设备划分为3类:
- sm:320vp<=width<520vp,典型设备为手机。
- md:520vp<=width<840vp,典型设备为折叠屏。
- lg:840vp<=width,典型设备为平板或PC。
根据用户使用场景,当操作设备尺寸为sm或md时,一般为竖向使用,此时用于切换应用页面的页签栏适合置于底部。当操作设备尺寸为lg时,一般为横向使用,此时页签栏适合置于左侧。
// MainPage.ets
@Entry
@Component
struct MainPage {...build() {SideBarContainer(SideBarContainerType.Embed) {LeftTabs({ bottomTabIndex: $bottomTabIndex }); // 侧边栏Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.End, justifyContent: FlexAlign.End }) {Tabs({ barPosition: BarPosition.End, index: 0, controller: this.controller }) {... // 页面内容}if (this.currentBreakpoint !== Const.LG) {BottomTabs({ bottomTabIndex: $bottomTabIndex }) // 底部栏,当屏幕尺寸不为"lg"时显示}}.width(Const.FULL_SIZE).backgroundColor($r('app.color.background_color'))}.showSideBar(this.currentBreakpoint === Const.LG) // 当屏幕尺寸为"lg"时显示侧边栏.showControlButton(false).sideBarWidth(Const.SIDEBAR_WIDTH).maxSideBarWidth(Const.SIDEBAR_WIDTH_MAX).minSideBarWidth(Const.SIDEBAR_WIDTH_MIN)}
}
各页面代码实现
首页
首页显示轮播图和“最近播放”、“为你推荐”两个列表,轮播图根据屏幕尺寸的区别,有显示数量的不同(sm为1,md为2,lg为3),列表使用具备自适应布局能力的List组件。
// HomeTabsComponent.ets
@Component
export struct HomeTabs {@Link currentBreakpoint: string;private scroller: Scroller = new Scroller();build() {Scroll(this.scroller) {GridRow({// 设置sm、md和lg的布局列数分别为4、8、12columns: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 },gutter: { x: $r('app.float.gutter_home') },breakpoints: { value: [Const.BREAKPOINTS_SM, Const.BREAKPOINTS_MD, Const.BREAKPOINTS_LG] }}) {GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {... // 标题}.height($r('app.float.title_height')).margin({ bottom: $r('app.float.home_margin1') })// 搜索栏在sm、md下占满全部列,在lg下占8列GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_8 } }) {... // 搜索栏}.height($r('app.float.home_grid_height1'))GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {Swiper() {...}.height($r('app.float.home_swiper_height')).itemSpace(Const.ITEM_SPACE)// 根据屏幕尺寸大小选择不同的轮播图数量.displayCount(this.currentBreakpoint === Const.LG ?Const.NUM_3 : (this.currentBreakpoint === Const.MD ? Const.NUM_2 : Const.NUM_1))}.height($r('app.float.home_grid_height2'))GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {... // ”最近播放”列表}.height($r('app.float.home_grid_height3'))GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {... // ”为你推荐”列表 }.height($r('app.float.home_column_height'))}.height(Const.FULL_SIZE)}...}
}
发现页
发现页使用栅格布局实现“一次开发,多端部署”能力,把sm设置为4列,md设置为8列,lg设置为12列。热播榜单在不同设备尺寸上分别占据4列、6列和8列。
// FindTabsComponent.ets
@Component
export struct FindTabs {private scroller: Scroller = new Scroller();build() {Scroll(this.scroller) {GridRow({// 设置sm、md和lg的布局列数分别为4、8、12columns: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 },gutter: { x: $r('app.float.gutter_find') },breakpoints: { value: [Const.BREAKPOINTS_SM, Const.BREAKPOINTS_MD, Const.BREAKPOINTS_LG] }}) {GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {... // 标题}.height($r('app.float.title_height'))LazyForEach(new FindDataSource(FindTabsList), (item: FindTabsItem) => {// 设置热播榜单在sm、md和lg上分别占据4、6、8列,并且设置offset属性保证在不同设备形态上都能保持居中GridCol({span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_6, lg: Const.GRID_8 },offset: {md: FindTabsList.indexOf(item) === Const.OFFSET_0 ? Const.OFFSET_1 : Const.OFFSET_2,lg: FindTabsList.indexOf(item) === Const.OFFSET_0 ? Const.OFFSET_2 : Const.OFFSET_4}}) {... // 榜单内容}}, (item: FindTabsItem) => JSON.stringify(item))}}...}
}
RK3568开发板上发现页的实际效果如图所示:
云盘页
云盘页的栅格划分和发现页相同,但是每个子组件在所有屏幕尺寸上都只占据2列。
// DriveTabsComponent.ets
@Component
export struct DriveTabs {private scroller: Scroller = new Scroller();build() {Scroll(this.scroller) {GridRow({// 设置sm、md和lg的布局列数分别为4、8、12columns: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 },gutter: { x : $r('app.float.gutter_drive') },breakpoints: { value: [Const.BREAKPOINTS_SM, Const.BREAKPOINTS_MD, Const.BREAKPOINTS_LG] }}) {GridCol({ span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 } }) {... // 标题}.height($r('app.float.title_height'))ForEach(DriveList, (item: DriveTabsItem) => {// 设置云盘内容在sm、md和lg上均占据2列GridCol({ span: { xs: Const.NUM_2, sm: Const.NUM_2, md: Const.NUM_2, lg: Const.NUM_2 } }) {... // 云盘内容}}, (item: DriveTabsItem) => JSON.stringify(item))}}...}
}
RK3568开发板上云盘页的实际效果如图所示:
个人页
个人页的栅格划分仍然和发现页相同,但子组件在sm、md形态下占满全部列,在lg形态下只占据8列。
// MineTabsComponent.ets
@Component
export struct MineTabs {private scroller: Scroller = new Scroller();build() {Scroll(this.scroller) {GridRow({// 设置sm、md和lg的布局列数分别为4、8、12columns: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_12 },gutter: { x: $r('app.float.gutter_mine') },breakpoints: { value: [Const.BREAKPOINTS_SM, Const.BREAKPOINTS_MD, Const.BREAKPOINTS_LG] }}) {// 设置个人页在sm和md上占满全部列,在lg上占8列,为保证居中在lg上设置offset为2列GridCol({span: { xs: Const.GRID_4, sm: Const.GRID_4, md: Const.GRID_8, lg: Const.GRID_8 },offset: { lg: Const.OFFSET_2 }}) {... // 个人页内容}}.height(Const.FULL_SIZE).backgroundColor($r('app.color.mine_background_color'))}...}
}
RK3568开发板上个人页的实际效果如图所示:
总结
您已经完成了本次Codelab的学习,并了解到以下知识点:
- 根据设备尺寸形态设计不同的页面布局。
- 使用栅格布局实现“一次开发,多端部署”能力。
为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→《HarmonyOS教学视频》
HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等.....视频教程
鸿蒙生态应用开发白皮书V2.0PDF:
获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF》
鸿蒙 (Harmony OS)开发学习手册
一、入门必看
- 应用开发导读(ArkTS)
- ……
二、HarmonyOS 概念
- 系统定义
- 技术架构
- 技术特性
- 系统安全
- ........
三、如何快速入门?《做鸿蒙应用开发到底学习些啥?》
- 基本概念
- 构建第一个ArkTS应用
- ……
四、开发基础知识
- 应用基础知识
- 配置文件
- 应用数据管理
- 应用安全管理
- 应用隐私保护
- 三方应用调用管控机制
- 资源分类与访问
- 学习ArkTS语言
- ……
五、基于ArkTS 开发
- Ability开发
- UI开发
- 公共事件与通知
- 窗口管理
- 媒体
- 安全
- 网络与链接
- 电话服务
- 数据管理
- 后台任务(Background Task)管理
- 设备管理
- 设备使用信息统计
- DFX
- 国际化开发
- 折叠屏系列
- ……
更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册》
相关文章:

HarmonyOS实战开发-一次开发,多端部署-视频应用
介绍 随着智能设备类型的不断丰富,用户可以在不同的设备上享受同样的服务,但由于设备形态不尽相同,开发者往往需要针对具体设备修改或重构代码,以实现功能完整性和界面美观性的统一。OpenHarmony为开发者提供了“一次开发&#x…...

关于v114之后的chromedriver及存放路径
使用selenium调用浏览器时,我一直调用谷歌浏览器,可浏览器升级后,就会再次遇到以前遇到过的各种问题,诸如:1、怎么关闭浏览器更新;2、去哪儿下载chromedriver;3、114版本之后的驱动去哪儿下载&a…...

http模块 服务器端如何响应(获取)静态资源?
一、静态资源与动态资源介绍: (1)静态资源 内容长时间不改变的资源。eg:图片、视频、css js html文件、字体文件... (2)动态资源 内容经常更新的资源。eg:百度首页、淘宝搜索列表... 二、服…...

基于PHP的校园招聘管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的校园招聘管理系统 一 介绍 此校园招聘管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为个人用户,企业和管理员三种。 技术栈:phpmysqlbootstrapphpstudyvscode 二…...

LLMs 可能在 2 年内彻底改变金融行业
在艾伦图灵研究所(The Alan Turing Institute)最新的一项研究中,我们看到了大型语言模型(Large Language Models,LLMs)的一种可能性。它有望通过检测欺诈行为、生成财务洞察以及自动化客户服务,…...
nodejs 中 yarn的安装和使用
Yarn是一个快速、可靠、易于使用的包管理工具,它是Facebook、Google、Tencent等公司使用的默认JavaScript包管理工具。Yarn可以帮助开发者在项目中管理依赖,确保不同环境之间的依赖一致性,并且加速依赖的下载和安装。 安装Yarn Yarn支持多种操作系统,包括macOS、Linux和W…...

软件工程学习笔记14——案例解析篇
案例解析篇 一、大型开源项目对软件工程的应用1、开发迭代过程 二、大厂是怎样应用软件工程的1、软件项目开发团队组成(1)软件开发团队规模小(2)没有专职测试(3)DevOps 文化 2、开发工具的使用3、项目开发流…...

【文件操作API的使用】
1.概念 这对聪明的你们来说简直就是,对吗。 那什么是文件操作符,文件操作又有哪些步骤呢? 文件操作符通常用于指代在计算机编程中用于处理文件的特殊符号或标识符。在很多编程语言中,文件操作符被用于打开、关闭、读取和写入文件…...
C++ 让类只在堆或栈上分配
1. 让类只在栈上或堆上分配内存 在C中,类的对象建立分为两种: 一种是静态建立,如A a; 另一种是动态建立,如A* ptrnew A;这两种方式是有区别的。 1、静态建立类对象:是由编译器为对象在栈空间…...
SpringMVC源码分析(九)--返回值解析器
1.返回值解析器介绍 返回值解析器用于解析Hanlder执行方法后的返回结果,例如将方法上标注有@ResponseBody注解的返回值解析成JSON、将方法返回的字符串作为视图名等 SpringMVC中默认的返回值解析器见RequestMappingHandlerAdapter#getDefaultReturnValueHandlers private L…...
京西商城——创建订单和获取订单接口
在之前的写过的接口中,我先后用了基于View和APIView来编写视图类 基于APIView类的时候相对于View会有很多便捷,但其实drf还在APIView的基础上又封装了一个 GenericAPIView 类,会大大减少了在编写视图时的重复代码和在修改代码时的工作量。 G…...

大话设计模式之模板方法模式
模板方法模式(Template Method Pattern)是一种行为设计模式,它定义了一个算法的框架,将特定步骤的实现延迟到子类中。模板方法模式通过在父类中定义算法的骨架,而将具体步骤的实现留给子类来完成,从而使子类…...

新model开发记录
模型使用 -- 用blender导出为 fbx ,修改渲染方式(点击模型->Materials->Extract Materials(将材质从fbx中 单独提取出来了)->Materials 选择 Shader -> SimpleURPToonLitExample 点开脸的材质,勾选第一条) 解决角色…...
ARMday1
1.总结keil5下载代码和编译代码需要注意的事项 答:下载代码时,确保stlink的驱动有效、魔术棒中硬件型号的连接 编译代码时,先将配置魔术棒里Debug中的Setting,将Flash中Reset and Run勾选上,并去除pack中的Enab…...
【C++风云录】创造视觉奇迹:探索C++图形编程的魅力与可能性
图形与界面:从SFML到Allegro,探索C图形编程的世界 前言 随着计算机图形技术和界面设计的快速发展,图形编程在软件开发中变得越来越重要。C作为一种功能强大的编程语言,为开发人员提供了丰富的图形编程工具和库。本文将介绍几个流…...

常见的Nginx+Redis+MQ+DB架构设计
三高,复杂的架构 SQRS CAP 缓存,限流 【Redis,缓存】 cache-aside 缓存cache:数据源的副本 store 1. Read/Write Through Pattern 读写穿透模式 redis:放当前在线用户,热点数据...

vue+elementUI搭建动态表头的表格
前提:以下代码是vue2项目结合elementUi完成的 数据结构 后端传来的数据是两个list,一个表头的list,一个表格内容的list // 表头 headTableAtts: [{ columnLabel: 姓名, columnName: name },{ columnLabel: 年龄, columnName: age },{ colu…...

【ENSP】交换机和交换机之间实现静态路由
1.概念 三层交换机只能在Vlanif逻辑口配置iP地址 2.实现方法 交换机允许对应vlan通行,配置vlanif的ip地址,做静态路由 3.静态路由配置方法 ip route-static 目的网段 子网掩码 下一跳设备 LSW1三层交换机配置 u t m sys vlan batch 10 20 …...
2024.2.18力扣每日一题——N叉树的前序遍历
2024.2.18 题目来源我的题解方法一 深度优先遍历(递归方式)方法二 迭代方式(栈实现) 题目来源 力扣每日一题;题序:589 我的题解 方法一 深度优先遍历(递归方式) 与二叉树的前序遍…...
Taro活动列表中,对某一个活动添加分享按钮
采用data-留下分享链接的拼接参数 1.在item文件中写按钮 openType“share” <ButtonclassName{classes.rowRightShareButton}openType"share"data-share-transfer-id{lastGiftingTransferId}data-share-picture-url{shareUrl}data-share-title{shareTitle}onClic…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...

【JVM】- 内存结构
引言 JVM:Java Virtual Machine 定义:Java虚拟机,Java二进制字节码的运行环境好处: 一次编写,到处运行自动内存管理,垃圾回收的功能数组下标越界检查(会抛异常,不会覆盖到其他代码…...

聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...

汽车生产虚拟实训中的技能提升与生产优化
在制造业蓬勃发展的大背景下,虚拟教学实训宛如一颗璀璨的新星,正发挥着不可或缺且日益凸显的关键作用,源源不断地为企业的稳健前行与创新发展注入磅礴强大的动力。就以汽车制造企业这一极具代表性的行业主体为例,汽车生产线上各类…...
【磁盘】每天掌握一个Linux命令 - iostat
目录 【磁盘】每天掌握一个Linux命令 - iostat工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景 注意事项 【磁盘】每天掌握一个Linux命令 - iostat 工具概述 iostat(I/O Statistics)是Linux系统下用于监视系统输入输出设备和CPU使…...

相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战
“🤖手搓TuyaAI语音指令 😍秒变表情包大师,让萌系Otto机器人🔥玩出智能新花样!开整!” 🤖 Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制(TuyaAI…...

CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
漏洞概览 漏洞名称:Apache Flink REST API 任意文件读取漏洞CVE编号:CVE-2020-17519CVSS评分:7.5影响版本:Apache Flink 1.11.0、1.11.1、1.11.2修复版本:≥ 1.11.3 或 ≥ 1.12.0漏洞类型:路径遍历&#x…...