作者:wanglei,华为UI编程框架技术专家

HarmonyOS自诞生以来,就是为满足分布式多设备应用场景而设计的,大到智慧屏、车机、平板,小到手机、手表。在多设备场景下进行应用UI界面开发,面临新的困难与挑战,如下图所示:

图1 多设备开发的挑战

为了使UI界面在色彩风格、屏幕尺寸、交互方式和组件功能等差异下仍能够正常显示,无疑需要开发人员花费大量精力在UI适配。开发人员常常需要实现多套界面布局(甚至多套工程),来满足不同设备间的设计差异。即使页面差异不大,也需要进行多设备测试,多次打包编译在设备或者模拟器上运行查看效果。后期维护过程中也需要不断查看不同设备下的兼容性,这些都极大地增加了应用开发者的工作量。

为了解决上述问题,简化开发者在多设备上的开发调试成本,我们提出了一次开发多端部署的设计理念,实现通过一套工程代码,一次开发上架,即可按需部署到不同设备。为了实现这一目标,我们从Harmony系统能力、ArkUI 3.0框架能力和开发工具能力三个方面,为开发者提供了多种适配方法和能力。

下面将一一为大家介绍。

一、HarmonyOS系统能力

首先介绍一下系统层面提供的能力。系统能力无需开发者进行页面调整,也无需进行业务逻辑调整,仅通过增加简单的几行配置描述,即可由系统进行多设备适配。系统能力与开发范式无关,因此在新的UI编程框架下仍可使用。下面我们依次介绍两种系统能力:模拟小窗和平行视界。

1. 模拟小窗

模拟小窗是最常用也是最简单的一种多设备适配方式,通过利用系统的悬浮窗能力,将低分辨率的应用,以悬浮窗口的形式在高分辨率屏幕上进行显示。常见的使用场景是手机应用在平板或PC上运行的场景,如下图所示:

图2 模拟小窗

模拟小窗的使用方式非常简单,只需在项目中config.json文件中增加两条描述,分别配置好应用的目标设备类型和响应的窗口尺寸,即可将低分辨率的应用运行在高分辨率设备上。示例代码如下:

{
“app”: {
...
“smartWindowSize”:“360*640”,
“smartWindowDeviceType”: [
“tablet”
]
},
...
}

这种使用方式能够良好地保证我们应用的展示效果和原始平台效果是一致的,无需开发者进行额外的界面的适配。但是这种方式也有局限,最显著的问题就是没有办法利用全部高分辨率的屏幕,整个屏幕内展示的数据量没有因屏幕分辨率的增加而增大,造成了屏幕上空间的浪费。为解决此问题,系统提供了另一种适配方案——平行视界。

2. 平行视界

系统针对折叠屏、平板设备提供了平行视界的能力,借助分屏显示的思想,将屏幕分为左右两个部分,分别显示应用相关联的两个页面内容。这样每个区域都能够保持良好的界面显示效果,也增加了屏幕内的有效数据量,良好地利用了屏幕显示区域。常用于新闻、购物类的场景,将相关的两个页面同时显示,如下图所示:

图3 平行视界

使用平行视界时,首先需要在config.json文件中配置metaData,声明支持平行视界。同时,还需要增加easygo.json文件进行页面路由关系配置,指导系统进行分屏显示。

平行视界的详细使用说明,可参考官网:

https://developer.harmonyos.com/cn/docs/documentation/doc-guides/multi-device-ui-app-multiplier-guidelines-0000001135848428

二、ArkUI 3.0框架能力

上述两种是通过配置即可实现的多端适配方案,使用简单,但是使用场景比较受限。为了更加精准地适配多设备界面,ArkUI 3.0框架提供了媒体查询、多态控件、原子布局和栅格系统,方便开发者选择合适的能力进行UI界面构建。

1. 媒体查询

媒体查询是CSS提供的标准能力,是响应式Web设计的关键部分。在新的UI范式中仍保留了此能力,作为最基础的UI响应式设计能力。在新的UI范式中,通过API接口方式对外提供媒体查询能力,可以探查的范围包括页面尺寸、设备分辨率、屏幕方向、页面宽高比、屏幕尺寸、设备类型、屏幕类型和主题模式。开发者可以根据不同的查询结果,进行定制化处理。比如:当屏幕方向变化时,可以调整界面内布局样式和组件显示效果;也可以根据设备类型不同,控制组件的显示和隐藏;并且当查询状态发生变化时,提供事件通知。

图4 媒体查询

2. 多态组件

UI界面构建离不开组件的使用。ArkUI 3.0框架为开发者提供了多态组件,通过组件将不同设备的样式风格和交互方式进行封装,替开发者完成大部分适配相关工作。开发者在使用多态组件时,无需考虑设备差异,只需关注功能实现即可。

下面通过一个示例来看看,相同的一套开发代码在手机、智慧屏和车机上展示的不同效果。

图5 多态组件

示例代码如下:

Column() {
Text("手机 / 平板")
.margin({top: 150})
Button("普通按钮")
.margin({top: 40})
.onClick(() => {
AlertDialog.show({title: '发现新版本', message: '当前使用移动数据网络,将消耗 XXX MB流量,是否更新',
primaryButton: {
value: '立即更新',
action: () => {}
},
secondaryButton: {
value: '以后再说',
action: () => {}
}})
})
}

产品设计人员常常不满足于使用系统默认样式,希望能够针对不同的平台使用自定义的风格样式。为了避免开发者逐个组件地进行样式调整,ArkUI 3.0框架将组件样式相关设置信息(如颜色、尺寸、圆角弧度、内容文本等)抽象出来形成了一个参数表,按照参数名称和参数值的方式进行映射。UI组件样式属性值都来自这张参数表,开发者和设计人员只需调整参数值,即可调整组件的显示效果。

3. 原子布局

多设备间差异最大的还是屏幕的分辨率,差异分辨率适配离不开自适应布局的能力。针对常见的开发场景,我们提炼了七种原子布局能力。这些布局可以独立使用,也可多种布局叠加使用。下面我们依次介绍这七种原子布局能力:

(1)折行布局:常用于横竖屏适配或手机向平板切换的场景。比如,竖直方向空间减少,但是水平方向上显示区域增加,这时可考虑使用折行布局,将竖直方向的排版变成水平方向。

图6 折行布局

折行布局利用了Flex布局的折行能力实现,配合布局约束设置,即可实现折行排布效果。示例代码如下:

Flex({direction: FlexDirection.Column, wrap: FlexWrap.Wrap}) {
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text("First Content")
.fontColor(Color.White)
.fontSize(30)
}
.constraintSize({minWidth: '50%', minHeight: '50%', maxWidth: 400})
.backgroundColor(Color.Gray)
Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) {
Text("Second Content")
.fontSize(30)
.fontColor(Color.White)
}
.constraintSize({minWidth: '50%', minHeight: '50%', maxWidth: 400})
.backgroundColor('rgb(207, 171, 103)')

(2)均分布局:常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。

图7 均分布局

示例代码如下:

@Entry
@Component
struct Index {
build() {
Flex({direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.SpaceEvenly}) {
Text('Hello')
.fontSize(20)
.borderColor(Color.Red)
.borderWidth(1)
Text('World')
.fontSize(20)
.borderColor(Color.Red)
.borderWidth(1)
Text('Ark')
.fontSize(20)
.borderColor(Color.Red)
.borderWidth(1)
Text('UI')
.fontSize(20)
.borderColor(Color.Red)
.borderWidth(1)
}
.width('100%')
.height('100%')
}
}

仅需配置为FlexAlign.SpaceEvenly模式,即可在Flex组件中将内容均分显示。

(3)隐藏布局:是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。比如媒体播放控制器,在宽屏场景可以完整显示全部控制项(包含播放、暂停、上一首、下一首、快进、快退,可能还有点赞和收藏按钮等),而在低分辨率场景只保留部分控制项(比如播放、暂停、上一首、下一首按钮)。

图8 隐藏布局

隐藏布局使用方式非常简单,只需通过displayPriority方法设置显示优先级,具有相同优先级的元素会同时显示或隐藏。在进行布局计算时,会根据当前可用空间,计算当前可显示组件进行显示。示例代码如下:

Row({space: 10}) {
Text('1')
.width(100)
.textAlign(TextAlign.Center)
.fontSize(40)
.backgroundColor(Color.Red)
.displayPriority(2)
Text('2')
.width(100)
.fontSize(40)
.textAlign(TextAlign.Center)
.backgroundColor(Color.Red)
.displayPriority(1)
Text('3')
.width(100)
.textAlign(TextAlign.Center)
.fontSize(40)
.backgroundColor(Color.Red)
.displayPriority(3)
Text('4')
.width(100)
.textAlign(TextAlign.Center)
.fontSize(40)
.backgroundColor(Color.Red)
.displayPriority(1)
Text('5')
.width(100)
.textAlign(TextAlign.Center)
.fontSize(40)
.backgroundColor(Color.Red)
.displayPriority(2)
}

(4)占比布局:是一种很常见的布局,就是根据容器尺寸按照比例进行显示。

图9 占比布局

通过设置百分比尺寸,即可实现比例调整。示例代码如下:

@Entry
@Component
struct Index {
build() {
Row() {
Text('Hello')
.fontSize(20)
.width('50%')
.backgroundColor(Color.Red)
Text('World')
.fontSize(20)
.width('20%')
.backgroundColor(Color.Yellow)
Text('Ark')
.fontSize(20)
.width('15%')
.backgroundColor(Color.Green)
Text('UI')
.fontSize(20)
.width('15%')
.backgroundColor(Color.Gray)
}
.width('100%')
.height('100%')
}
}

(5)拉伸缩放布局:组件尺寸跟随父容器尺寸变化,产生拉伸或缩放的展示效果。

图10 拉伸缩放布局

通过设置相对容器的比例,实现拉伸或缩放的展示效果。示例代码如下:

Row() {
Image($r('app.media.background'))
.objectFit(ImageFit.Fill)
.width('100%')
.height('100%')
}

(6)固定宽高比布局:在拉伸缩放时保持自身宽高比,通常用于图片缩放场景中,可保持图片显示效果正常,避免图片被拉长或压瘪,引起显示失真。

图11 固定宽高比布局

通过设置宽高比,保持按照固定宽高比进行拉伸显示,保障图片不会产生变形。示例代码如下:

Row() {
Image($r('app.media.background'))
.objectFit(ImageFit.Fill)
.width('100%')
.height('100%')
.aspectRatio(1.2)
}

(7)延伸布局:根据尺寸调整内容显示数量,主要是通过像列表这样的能力来实现。

图12 延伸布局

根据宽度不同,显示不同数量的内容,并且可以通过滑动操作,显示出更多内容。示例代码如下:

@Entry
@Component
struct Index {
private data: string[] = ['Hello', 'World', 'Ark', 'UI', 'This', 'Is', 'Layout', 'Demo']
build() {
Flex({direction:FlexDirection.Column, justifyContent: FlexAlign.Center}) {
List({space: 10}) {
ForEach(this.data, (item) => {
ListItem() {
Text(item)
.fontSize(20)
.width(80)
}.height(80)
.backgroundColor(Color.Red)
})
}
.listDirection(Axis.Horizontal)
.width('100%')
.height(100)
}
.width('100%')
.height('100%')
}
}

此示例通过List作为布局容器,进行内容线性排布,并支持滑动响应。

4. 栅格系统

ArkUI 3.0框架还提供了完整的栅格系统。所谓栅格系统是来自UX设计中的栅格设计,将屏幕宽度按照不同数量的栅格划分为不同的列,组件的尺寸占用一个或多个栅格。采用这种方式进行设计的布局系统,称之为栅格系统。使用栅格系统,可以屏蔽屏幕分辨率的差异,在不同分辨率的屏幕上保持显示内容的相对尺寸一致。

常见的栅格系统有8栅格系统和12栅格系统,而我们提供的是动态栅格系统,可以根据不同的屏幕尺寸,动态地调整栅格数量。使用动态栅格系统时,不同分辨率的设备使用不同的栅格配置,比如:手机竖屏采用4栅格系统,手机横屏和折叠屏采用8栅格系统,大屏采用12栅格系统。

图13 动态栅格系统

为了方便开发者使用,ArkUI 3.0框架提供了栅格布局容器GridContainer。下面我们来看一个示例,代码如下:

Stack() {
GridContainer({sizeType: SizeType.Auto}) {
Row() {
Button('OK')
.fontSize(30)
.gridSpan(2)
.useSizeType({lg: 4})
}
}
}

栅格布局容器可以设置为固定栅格数,也可以设置为Auto模式。此示例采用的是Auto模式,栅格布局容器会根据宽度动态调整栅格数量。同时通过useSizeType属性方法,可以设置在不同栅格模式下,组件占用的栅格数量。比如:“.useSizeType({lg: 4})”表示在large栅格系统(即12栅格系统)中,Button组件宽度占用4栅格显示。

因此,此示例在手机和平板上的显示效果如下:

图14 显示效果

三、开发工具能力

除了上面的系统能力和ArkUI 3.0框架能力外,我们还从开发工具(DevEco Studio)方面,为开发者提供了各种各样的开发模板,以及多设备预览等能力,减少开发者的开发调试成本,提升开发效率。

1. 开发模板

开发模板主要包括工程模板和卡片模板。

  • 工程模板:DevEco Studio预置了丰富的工程模板,可以根据工程向导轻松创建适应于各类设备的工程,并自动生成对应的代码和资源模板。创建工程时,开发者可以挑选合适的工程模板。
  • 卡片模板:DevEco Studio提供了多种类型的卡片模板,开发者可以根据需要展示的信息类型灵活选择模板,快速构建服务卡片。

图15 工程模板和卡片模板

2. 多设备预览

DevEco Studio还支持多设备预览能力,开发者可以在同一窗口中,同时查看多种设备下UI界面的展示效果。预览器与真机设备采用相同渲染引擎和UI框架,可以最大程度地做到预览效果与真机运行效果的一致。以下动图展示了多设备预览能力:

感兴趣的小伙伴,可以从官网下载和体验DevEco Studio新版本:https://developer.harmonyos.com/cn/develop/deveco-studio

四、结束语

实现完美的一次开发多端部署效果,离不开开发者的参与。UI开发框架和系统在实现一次开发多端部署的过程中进行了初步的探索,也期待开发者能反馈更多的多设备UI开发过程中的痛点,以及期待系统框架提供的能力。

欢迎开发者和我们一起,在开源社区将一次开发多端部署的能力丰富起来!

HDC2021技术分论坛:ArkUI 3.0让多设备开发更简单!的更多相关文章

  1. HDC2021技术分论坛:组件通信、硬件池化,这些创新技术你get了吗?

    作者:ligang 华为分布式硬件技术专家,sunbinxin 华为应用框架技术专家 HarmonyOS是一款全新的分布式操作系统,为开发者提供了元能力框架.事件通知.分布式硬件等分布式技术,使能开发 ...

  2. HDC2021技术分论坛:如何高效完成HarmonyOS分布式应用测试?

    作者:liuxun,HarmonyOS测试架构师 HarmonyOS是新一代的智能终端操作系统,给开发者提供了设备发现.设备连接.跨设备调用等丰富的分布式API.随着越来越多的开发者投入到Harmon ...

  3. HDC2021技术分论坛:异构组网如何解决共享资源冲突?

    作者:lijie,HarmonyOS软总线领域专家 相信大家对HarmonyOS的"超级终端"比较熟悉了.那么,您知道超级终端场景下的多种设备在不同环境下是如何组成一个网络的吗?这 ...

  4. HDC2021技术分论坛:进程崩溃/应用卡死,故障频频怎么办?

    ​作者:jiwenqiang,DFX技术专家 提到开发一个产品,我们通常首先想到的是要实现什么样的功能,但是除了功能之外,非功能属性也会很大程度上影响一个产品的体验效果,比如不定时出现的应用卡死.崩溃 ...

  5. HDC2021技术分论坛:“积木拼装”,HarmonyOS弹性部署大揭秘!

    作者:peitaiyi,华为终端OS产品交付专家 HarmonyOS是一款面向万物互联时代的.全新的分布式操作系统.在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力.适配多种终 ...

  6. HDC技术分论坛:HarmonyOS新一代UI框架的全面解读

    作者:yuzhiqiang,UI编程框架首席技术专家 在Harmony 3.0.0开发者预览版中,包含了新一代的声明式UI框架ArkUI 3.0.多语言跨平台编译器ArkCompiler 3.0.跨端 ...

  7. APICloud数据云3.0 -- 让后端业务更简单

    近年来,各类移动端应用层出不穷,app.小程序已成为企业业务数字化的必然选择,围绕互联网产品的技术创新与开发者生态,正在历经行业发展的又一次革新. APICloud作为国内领先的移动应用开发平台,一直 ...

  8. seldom 2.0 让接口自动化测试更简单

    前言 HTTP接口测试很简单,不管工具.框架.还是平台,只要很的好的几个点就是好工具. 测试数据问题:比如删除接口,重复执行还能保持结果一致,必定要做数据初始化. 接口依赖问题:B接口依赖A的返回值, ...

  9. paip.2013年技术趋势以及热点 v3.0 cao

    paip.2013年技术趋势以及热点 v3.0 cao 作者Attilax  艾龙,  EMAIL:1466519819@qq.com  来源:attilax的专栏 地址:http://blog.cs ...

  10. paip.2013年技术趋势以及热点 v2.0 cae

    paip.2013年技术趋势以及热点 v2.0 cae HTML5 多核编程 物联网 可穿戴计算设备 3. 物联网 无论是M2M(机器对机器)通信应用,还是NFC(进距离通信)技术,都是物联网的组成部 ...

随机推荐

  1. Nebula Graph 源码解读系列|客户端的通信秘密——fbthrift

    概述 Nebula Clients 给用户提供了多种编程语言的 API 用于和 Nebula Graph 交互,并且对服务端返回的数据结构进行了重新封装,便于用户使用. 目前 Nebula Clien ...

  2. 在anaconda中为jupyter安装代码自动补全或代码自动提示功能,jupyter nbextensions不显示拓展,另附格式化代码插件的安装方法

    操作步骤 进入命令行环境.我使用的是conda.有两种方式进入命令行. 方法1:通过anconda navigator界面,选择environments,选择对应环境名,选择open terminal ...

  3. MySQL之过滤条件

    [一]筛选过滤条件 [1]查询语句 -- 查询当前表中的指定字段的数据 select id,name from emp where id > 3; [2]创建数据表 create databas ...

  4. Node.js解压版的环境配置及相关常用命令

    下载 进入node.js官网的下载页面node.js下载页面,选择合适的版本进行下载 配置 1.设置环境变量 随便找一个地方,将文件解压出来 复制当前的路径,我的电脑右键,打开属性,左边有个高级系统配 ...

  5. C++ 中的关联,聚合,组合 以及 它们的生命周期。

    关联,C++使用指针实现,两者到关系最弱,并且可以两向关联,B* A::b 与 A* B::a 可以并存,两者间没有明确的ownership关系,为什么不是引用,因为引用没有办法实现相向引用,这会是一 ...

  6. makefile 编写要点

    PS:要转载请注明出处,本人版权所有. PS: 这个只是基于<我自己>的理解, 如果和你的原则及想法相冲突,请谅解,勿喷. 前置说明   本文作为本人csdn blog的主站的备份.(Bl ...

  7. 【STM32F4 HAL】MPU6050食用

    关于MPU6050模块的食用>_<(本人比较菜,写的不好或有错误的地方欢迎大佬指出) 最近学校冬令营发了个MPU6050模块,第一次弄也花了我花了不少时间,于是就把其中一些步骤以及要点简单 ...

  8. 天天用defineEmits宏函数,竟然不知道编译后是vue2的选项式API?

    前言 我们每天都在使用 defineEmits 宏函数,但是你知道defineEmits 宏函数经过编译后其实就是vue2的选项式API吗?通过回答下面两个问题,我将逐步为你揭秘defineEmits ...

  9. java 控制台 输出进度条

    效果  代码 public static void main(String[] args) { int total = 100; for (int i = 0; i < total; i++) ...

  10. DW:优化目标检测训练过程,更全面的正负权重计算 | CVPR 2022

    论文提出自适应的label assignment方法DW,打破了以往耦合加权的惯例.根据不同角度的一致性和非一致性指标,动态地为anchor分配独立的pos权重和neg权重,可以更全面地监督训练.此外 ...