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开发板为例,参照以下步骤进行:

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

2.搭建烧录环境。

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

3.搭建开发环境。

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

代码结构解读

本篇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、12
        columns: { 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、12
        columns: { 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、12
        columns: { 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、12
        columns: { 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的学习,并了解到以下知识点:

  1. 根据设备尺寸形态设计不同的页面布局。
  2. 使用栅格布局实现“一次开发,多端部署”能力。

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的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)开发学习手册》

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java与数学】若不等式x^2-a*x+a<0的解集中恰有3个整数,求a的范围?

【分析】 既然不等式存在解集&#xff0c;说明一元二次方程x^2-a*xa0有解&#xff1b; 解之间横跨三个整数&#xff0c;说明Δ大于0&#xff1b; 三个整数必然是连续的&#xff0c;因为f(x)x^2-a*xa最多只与x存在两个交点&#xff0c;这是题设里的隐含条件。 【传统解法】 …

2024 3.23~3.29周报

上周工作 SVInvNet论文研读 本周计划 加入DenseNet&#xff0c;修改网络架构&#xff0c;跑代码 总结 DenseNet 密集块&#xff1a;DenseNet将网络分成多个密集块&#xff08;Dense Block)。在每个密集块内&#xff0c;每一层都连接到前面所有的层。这种跳跃连接有助于解…

Mac m1 Flink的HelloWorld

首先在官方下载Downloads | Apache Flink 下载好压缩包后解压&#xff0c;得到Flink文件夹 进入&#xff1a;cd flink-1.19.0 ls 查看里面的文件&#xff1a; 执行启动集群 ./bin/start-cluster.sh 输出显示它已经成功地启动了集群&#xff0c;并且正在启动 standalonesessio…

Vue ElementPlus Input输入框

Input 输入框 通过鼠标或键盘输入字符 input 为受控组件&#xff0c;它总会显示 Vue 绑定值。 通常情况下&#xff0c;应当处理 input 事件&#xff0c;并更新组件的绑定值&#xff08;或使用v-model&#xff09;。否则&#xff0c;输入框内显示的值将不会改变。不支持 v-mode…

Oracle 低代码平台 Apex 最新版本 23.2 安装过程

趁春节快结束前&#xff0c;安装了一把APEX &#xff0c;到目前为此&#xff0c;APEX最新版本为23.2&#xff0c;23.2和21版本有一些变化&#xff0c;只是用于验证&#xff0c;我 是使用的单独模式&#xff0c;没有安装TOMAT&#xff0c;下面列一下安装过程&#xff1a; 1.环境…

机器学习——最优化模型

最优化模型的概述&#xff1a; 从某种程度上说&#xff0c;我们的世界是由最优化问题组成的。每一天&#xff0c;我们的生活都面临无数的最优化问题&#xff1a;上班怎么选择乘车路线&#xff0c;才能舒服又快速地到达公司&#xff1b;旅游如何选择航班和宾馆&#xff0c;既省…

[flink 实时流基础] 转换算子

flink学习笔记 数据源读入数据之后&#xff0c;我们就可以使用各种转换算子&#xff0c;将一个或多个DataStream转换为新的DataStream。 文章目录 基本转换算子&#xff08;map/ filter/ flatMap&#xff09;聚合算子&#xff08;Aggregation&#xff09;按键分区&#xff08;…

【隐私计算实训营006隐语PIR介绍及开发实践】

1. 隐语实现PIR总体介绍 隐匿查询&#xff08;Private Information Retrieval PIR&#xff09;定义 按服务器数量分类 单服务器方案&#xff08;Single Server&#xff09;多服务器方案&#xff08;Multi-Server&#xff09; 按查询类型分类 Index PIRKeyword PIR 隐语目前…

基于两个单片机串行通信的电子密码锁设计

1.功能 电子号码锁在实际应用中应该有两部分&#xff0c;一部分在外部&#xff0c;有键盘部分和密码显示&#xff1b;另一部分内部&#xff0c;设置密码、显示密码。使用单片机自身带有的串口可以很方便的实现单片机之间的通信&#xff0c;使输入的密码值传送到主机检验是否是…

nginx的https与动态负载均衡

nginx的https 证书可以根据你的域名和服务器服务商去进行签发 , 比如 : 阿里云 腾讯云 百度云 华为云等 这里使用的是腾讯云 : 下载证书 : 选择 nginx: 下载之后传递到服务器上。 下面开始配置nginx的https: 1. 解压下载的证书包 cd /etc/ssl unzip xxcc.dwa_nginx.zip mv…

【A-010】基于SSH的宠物狗商城系统(含论文)

【A-010】基于SSH的宠物狗商城系统&#xff08;含论文&#xff09; 开发环境&#xff1a; Eclipse/MyEclipse、Tomcat8、Jdk1.8 数据库&#xff1a; MySQL 项目介绍&#xff1a; 在科学技术飞速发展的今天&#xff0c;互联网成为人们快速获取、发布和传递信息的重要渠道&am…

Cesium实现渐变面

一、效果图 二、实现思路 使用着色器&#xff0c;通过纹理坐标和其他参数计算出材质的颜色和透明度。通过给定的颜色、漫反射强度和透明度&#xff0c;计算出最终的反射颜色和透明度&#xff0c;并且根据给定的中心点位置和当前像素的纹理坐标&#xff0c;计算出距离中心的距离…

怎么快速上手虚拟化(容器)技术——以 Docker 为例

Docker 整体介绍 Docker 是一种使用 Go 语言开发的容器工具。所谓容器&#xff0c;实际上是一种虚拟化技术&#xff0c;用于为应用提供虚拟化的运行环境&#xff0c;相较于虚拟机具有轻量级、低延迟的特性。 下面是对上述介绍的说明&#xff1a; 应用程序运行需要一定的依赖…

在 C#和ASP.NET Core中创建 gRPC 客户端和服务器

关于gRPC和Google protobuf gRPC 是一种可以跨语言运行的现代高性能远程过程调用 (RPC) 框架。gRPC 实际上已经成为 RPC 框架的行业标准&#xff0c;Google 内外的组织都在使用它来从微服务到计算的“最后一英里”&#xff08;移动、网络和物联网&#xff09;的强大用例。 gRP…

canvas画图,画矩形可拖拽移动,可拖拽更改尺寸大小

提示&#xff1a;canvas画图&#xff0c;画矩形&#xff0c;圆形&#xff0c;直线&#xff0c;曲线可拖拽移动 文章目录 前言一、画矩形&#xff0c;圆形&#xff0c;直线&#xff0c;曲线可拖拽移动总结 前言 一、画矩形&#xff0c;圆形&#xff0c;直线&#xff0c;曲线可拖…

壁纸小程序Vue3(分类页面和用户页面基础布局)

1.配置tabBar pages.json "tabBar": {"color": "#9799a5","selectedColor": "#28B389","list": [{"text": "推荐","pagePath": "pages/index/index","iconPath&quo…

6.6物联网RK3399项目开发实录-驱动开发之LED灯的使用(wulianjishu666)

90款行业常用传感器单片机程序及资料【stm32,stc89c52,arduino适用】 链接&#xff1a;https://pan.baidu.com/s/1M3u8lcznKuXfN8NRoLYtTA?pwdc53f LED 使用 前言 AIO-3399J 开发板上有 2 个 LED 灯&#xff0c;如下表所示&#xff1a; 可通过使用 LED 设备子系统或者直…

EXCEL-VB编程实现自动抓取多工作簿多工作表中的单元格数据

一、VB编程基础 1、 EXCEL文件启动宏设置 文件-选项-信任中心-信任中心设置-宏设置-启用所有宏 汇总文件保存必须以宏启动工作簿格式类型进行保存 2、 VB编程界面与入门 参考收藏 https://blog.csdn.net/O_MMMM_O/article/details/107260402?spm1001.2014.3001.5506 二、…

云计算探索-剖析虚拟化技术

引言 虚拟化技术&#xff0c;作为现代信息技术架构的核心构成元素&#xff0c;以其独特的资源抽象与模拟机制&#xff0c;成功地瓦解了物理硬件与操作系统间的刚性连接&#xff0c;开创了一个资源共享、灵活调配的崭新天地。本文将详细解析虚拟化技术的内涵、发展历程、分类及特…

Android 天气APP(二)获取定位信息

<LinearLayout xmlns:android“http://schemas.android.com/apk/res/android” xmlns:app“http://schemas.android.com/apk/res-auto” xmlns:tools“http://schemas.android.com/tools” android:gravity“center” android:layout_width“match_parent” android:la…