未验证 提交 8d09ed80 编写于 作者: O openharmony_ci 提交者: Gitee

!9901 一多文档修改

Merge pull request !9901 from zengyawen/master
# 一次开发,多端部署 # 一次开发,多端部署
- [前言](about-this-document.md) - [前言](foreword.md)
- [简介](introduction.md) - [简介](introduction.md)
- 应用UX设计 - [从一个例子开始](start-with-a-example.md)
- [设计原则和要点](design-principles.md) - 应用UX设计
- 应用架构设计 - [设计原则和要点](design-principles.md)
- [应用导航结构设计要求](navigation-design.md) - 应用架构设计
- [应用页面结构设计](page-design.md) - [应用导航结构设计要求](navigation-design.md)
- 界面布局 - [应用页面结构设计](page-design.md)
- [概述](layout-design-intro.md) - 界面布局
- 布局基础 - [概述](interface-layout-design-intro.md)
- [栅格系统](layout-grid.md) - 布局基础
- [自适应布局](layout-adaptive.md) - [栅格系统](design-grid.md)
- [响应式布局](layout-responsive.md) - [自适应布局](design-adaptive-layout.md)
- [布局基础运用案例](layout-design-cases.md) - [响应式布局](design-responsive-layout.md)
- 人机交互 - [布局基础运用案例](design-layout-cases.md)
- [交互基础](interaction-basics.md) - 人机交互
- [常见输入方式](common-input-modes.md) - [交互基础](interaction-basics.md)
- [交互事件归一](design-interaction-events-unification.md) - [常见输入方式](common-input-modes.md)
- 视觉风格 - [交互事件归一](design-interaction-event-normalization.md)
- [视觉基础](visual-style-basics.md) - 视觉风格
- [色彩](visual-style-color.md) - [视觉基础](visual-basics.md)
- [字体](visual-style-font.md) - [色彩](visual-style-color.md)
- [图标](visual-style-icon.md) - [字体](visual-style-font.md)
- [多态控件](design-polymorphic-components.md) - [图标](visual-style-icon.md)
- [设计自检表](design-checklist.md) - [多态控件](design-polymorphic-controls.md)
- [资源](resource.md) - [设计自检表](design-checklist.md)
- [IDE使用](ide-usage.md) - [设计交付](design-delivery.md)
- 一多能力的页面开发介绍 - [资源](design-resources.md)
- 布局能力 - [工程管理](ide-using.md)
- [布局能力简介](layout-intro.md) - 页面开发的一多能力介绍
- 自适应布局 - [简介](page-development-intro.md)
- [自适应布局简介](adaptive-layout-intro.md) - 布局能力
- [拉伸能力](adaptive-layout-stretching.md) - [布局简介](layout-intro.md)
- [均分能力](adaptive-layout-equalization.md) - [自适应布局](adaptive-layout.md)
- [占比能力](adaptive-layout-proportion.md) - [响应式布局](responsive-layout.md)
- [缩放能力](adaptive-layout-scaling.md) - [典型布局场景](typical-layout-scenario.md)
- [延伸能力](adaptive-layout-extension.md) - 典型页面场景
- [隐藏能力](adaptive-layout-hiding.md) - [应用市场首页](appgallery-home-page.md)
- [折行能力](adaptive-layout-wrapping.md) - [音乐专辑页](music-album-page.md)
- 响应式布局 - [交互归一](interaction-event-normalization.md)
- [栅格断点系统](grid-breakpoint.md) - [多态组件](polymorphic-controls.md)
- [媒体查询](media-query.md) - [资源使用](resource-usage.md)
- [典型场景](responsive-layout-cases.md) - [功能开发的一多能力介绍](development-intro.md)
- [交互归一](interaction-events-unification.md) - [案例应用](case.md)
- [多态组件](polymorphic-components.md) - [常见问题](faq.md)
- [资源使用](resource-usage.md)
- [一多能力的功能开发介绍](development-intro.md)
- 案例应用
- 短信应用
- [概览](sms-intro.md)
- 会话详情页面
- [页面结构](sms-session-page-structure.md)
- [顶部标题栏](sms-session-page-title-bar.md)
- [底部输入栏](sms-session-page-input-field.md)
- [信息列表](sms-session-page-message-list.md)
- [组合成型](sms-session-page-combined.md)
- [总结](sms-session-summary.md)
- [桌面应用](cases-home-screen.md)
- [常见问题](faqs.md)
# 前言
本指导的目的是快速及全面地指导读者使用OpenHarmony提供的“一次开发,多端部署”(本指导中简称“一多”)能力开发多设备应用。在应用开发前,开发者应尽可能全面考虑应用支持多设备的情况,避免在后期加入新的类型设备时需要对应用架构进行大幅调整。
## 本指导面向的读者
本指导适合开发OpenHarmony应用的UX设计师、应用开发人员,本指导书统称为“应用开发者”。这两者是根据开发角色不同而进行的区分。对于个人或者规模较小的应用,两者可能是同一个个体,但应当从角色上加以区分。
## 如何阅读本指导
应用在需求明确后,开发过程大致分为:应用设计(包含界面UX设计、业务功能设计)- 工程设计和创建 - 功能代码实现。本指导也是基于这个流程进行的内容编排。
阅读本文档时,应尽量按照章节顺序进行阅读。如果区分开发角色,那么UX设计师可以仅阅读第3章,而开发人员可以从第4章开始阅读。但无论何种角色,我们强烈建议阅读第2章。
本文档各章节简介如下:
- 第1章[前言](about-this-document.md)说明本指导面向的读者、如何阅读本指导等,指引读者更好地阅读。
- 第2章[简介](introduction.md)简短介绍了“一多”的背景、定义、目标、以及用于指导后续开发的一些基础知识。
- 第3章[应用UX设计](design-principles.md)介绍了应用UX设计理念。主要阐述了应用设计之初UX设计的原则和要点。该章节主要面向应用的UX设计师。
UX设计原则应该考虑多设备的“差异性” 、“一致性”、“灵活性”、“兼容性”。
UX设计要点则从6个方面阐述如何进行多设备应用设计,分别是“自适应应用架构”、“响应式界面布局”、“交互归一”、“视觉参数化”、“多态控件”、“针对性优化”。
最后,给出设计自检表,用于检查应用UX设计是否合理。
- 第4章[IDE使用](ide-usage.md)介绍了从工程角度如何开始开发应用,这非常有用,让读者可以直接上手创建多设备应用的工程,是后面学习“一多”能力的上手基础。
- 第5章[一多能力的页面开发介绍](layout-intro.md)、第6章[一多能力的功能开发介绍](development-intro.md)介绍了OpenHarmony提供的“一多”能力,其中每个能力都提供了代码示例和UX效果,让读者可以快速学习“一多”能力。
- 第7章提供了两个案例应用,阐述了从应用设计到开发这一过程中如何实践前面章节介绍的设计思路或“一多”能力,让读者可以整体上掌握“一多”在应用开发过程中的知识。
- 第8章[常见问题](faqs.md)提供了常见问题(FAQ),方便读者查阅。
本指导在介绍过程中还包括一些“说明”。这些“说明”,表示例外情况或者额外信息的补充。
# 均分能力
均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。
均分能力通常通过使用 **Flex均分布局**[Flex组件](../../reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly)实现,即子元素在Flex主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 均分能力是特殊场景下拉伸能力的简单实现。也可以借助其它方式实现均分能力,如在每个组件间添加Blank组件等。
## 示例:
父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。
![zh-cn_image_0000001291935425](figures/zh-cn_image_0000001291935425.gif)
```ts
@Entry
@Component
struct EquipartitionCapabilitySample {
const list: number [] = [0, 1, 2, 3];
@State rate: number = 0.6;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Column() {
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
// 均匀分配父容器主轴方向的剩余空间
Flex({ justifyContent: FlexAlign.SpaceEvenly }) {
ForEach(this.list, (item) => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
}
.width(this.rate * 100 + '%')
.height(222)
.padding({ top: 16 })
.backgroundColor('#FFFFFF')
.borderRadius(16)
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 延伸能力
延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。
延伸能力通常有两种实现方式:
- 通过[List组件](../../reference/arkui-ts/ts-container-list.md)实现。
- 通过[Scroll组件](../../reference/arkui-ts/ts-container-scroll.md)配合[Row组件](../../reference/arkui-ts/ts-container-row.md)[Column组件](../../reference/arkui-ts/ts-container-column.md)实现。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> List、Row或Column组件中子节点的在页面显示时就已经全部完成了布局计算及渲染,只不过受限于父容器尺寸,用户只能看到一部分。随着父容器尺寸增大,用户可以看到的子节点数目也相应的增加。用户还可以通过手指滑动触发列表滑动,查看被隐藏的子节点。
## 示例:
当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。
分别通过List组件实现及通过Scroll组件配合Row组件实现。
![zh-cn_image_0000001245295918](figures/zh-cn_image_0000001245295918.gif)
(1)通过List组件实现。
```ts
@Entry
@Component
struct ExtensionCapabilitySample1 {
@State rate: number = 0.60;
const appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Row({ space: 10 }) {
// 通过List组件实现隐藏能力
List({ space: 10 }) {
ForEach(this.appList, (item) => {
ListItem() {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.listDirection(Axis.Horizontal)
.width('100%')
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
(2)通过Scroll组件配合Row组件实现。
```ts
@Entry
@Component
struct ExtensionCapabilitySample2 {
private scroller: Scroller = new Scroller()
@State rate: number = 0.60;
@State appList: number [] = [0, 1, 2, 3, 4, 5, 6, 7];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 8, max: 60, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
// 通过Scroll和Row组件实现隐藏能力
Scroll(this.scroller) {
Row({ space: 10 }) {
ForEach(this.appList, () => {
Column() {
Image($r("app.media.icon")).width(48).height(48).margin({ top: 8 })
Text('App name')
.width(64)
.height(30)
.lineHeight(15)
.fontSize(12)
.textAlign(TextAlign.Center)
.margin({ top: 8 })
.padding({ bottom: 15 })
}.width(80).height(102)
})
}
.padding({ top: 16, left: 10 })
.height(118)
.borderRadius(16)
.backgroundColor(Color.White)
}
.scrollable(ScrollDirection.Horizontal)
.width(this.rate * 100 + '%')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 隐藏能力
隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。
隐藏能力通过设置**布局优先级**(displayPriority属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。
可以访问[布局约束](../../reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解displayPriority属性的详细信息。
## 示例:
父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。
![zh-cn_image_0000001245136646](figures/zh-cn_image_0000001245136646.gif)
```ts
@Entry
@Component
struct HiddenCapabilitySample {
@State rate: number = 0.45;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 10, max: 45, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column,
justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.favorite"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
Image($r("app.media.down"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.pause"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(3) // 布局优先级
Image($r("app.media.next"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(2) // 布局优先级
Image($r("app.media.list"))
.width(48)
.height(48)
.objectFit(ImageFit.Contain)
.margin({ left: 12, right: 12 })
.displayPriority(1) // 布局优先级
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 自适应布局简介
多设备间最大的差异是屏幕分辨率,差异分辨率适配离不开自适应布局的能力。针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力。这些布局可以独立使用,也可多种布局叠加使用。
| 自适应布局类别 | 自适应布局能力 | 使用场景 |
| -------- | -------- | -------- |
| 自适应拉伸 | [拉伸能力](adaptive-layout-stretching.md) | 容器组件尺寸发生变化时,增加或减小的空间**全部分配**给容器组件内**指定区域**。 |
| [均分能力](adaptive-layout-equalization.md) | 容器组件尺寸发生变化时,增加或减小的空间**均匀分配**给容器组件内**所有空白区域**。 ||
| 自适应缩放 | [占比能力](adaptive-layout-proportion.md) | 子组件的宽高**按照预设的比例**,随容器组件发生变化。 |
| [缩放能力](adaptive-layout-scaling.md) | 子组件的宽高**按照预设的比例**,随容器组件发生变化,且变化过程中子组件的**宽高比不变**。 ||
| 自适应延伸 | [延伸能力](adaptive-layout-extension.md) | 容器组件内的子组件,按照其**在列表中的先后顺序**,随容器组件尺寸变化显示或隐藏。 |
| [隐藏能力](adaptive-layout-hiding.md) | 容器组件内的子组件,按照其**预设的显示优先级**,随容器组件尺寸变化显示或隐藏。**相同显示优先级的子组件同时显示或隐藏**。 ||
| 自适应折行 | [折行能力](adaptive-layout-wrapping.md) | 容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,**自动换行**。 |
下面我们依次介绍这几种自适应布局能力。
# 占比能力
占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。
占比能力通常有两种实现方式:
- 将子组件的宽高设置为父组件宽高的百分比,详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)[长度类型](../../ui/ts-types.md#长度类型)
- 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重,详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)
- 当父容器尺寸确定时,其子组件按照开发者配置的权重比例分配父容器中主轴方向的空间。
- 仅当父容器是Row、Colomn或者Flex时,layoutWeight属性才会生效。
- 设置layoutWeight属性后,组件本身的尺寸会失效。比如同时设置了.width('40%')和.layoutWeight(1),那么只有.layoutWeight(1)会生效。
layoutWeight存在使用限制,所以实际使用过程中大多通过将子组件宽高设置为父组件的百分比来实现占比能力。
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 占比能力在实际开发中使用的非常广泛,可以通过很多不同的方式实现占比能力,如还可以通过[Grid组件](../../reference/arkui-ts/ts-container-grid.md)的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格(本章后文将详细介绍栅格系统)中占据不同的列数来实现占比能力。本小节仅介绍最基础和常用的实现方式,局限性较大或比非常小众的实现方式,本文不再展开介绍。
## 示例:
简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。
将三个按钮的.layoutWeight(1)分别替换为.width('33%')、.width('34%')、.width('33%'),也可以实现与当前同样的显示效果。
![zh-cn_image_0000001292374353](figures/zh-cn_image_0000001292374353.gif)
```ts
@Entry
@Component
struct ProportionCapabilitySample {
@State rate: number = 0.5;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: 100, min: 25, max: 50, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Row() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.down"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.pause"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
.backgroundColor('#66F1CCB8')
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Image($r("app.media.next"))
.width(48)
.height(48)
}
.height(96)
.layoutWeight(1) // 设置子组件在父容器主轴方向的布局权重
}
.width(this.rate * 100 + '%')
.height(96)
.borderRadius(16)
.backgroundColor('#FFFFFF')
}
this.slider()
}
.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 缩放能力
缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。
缩放能力通过使用百分比布局配合**固定宽高比**(aspectRatio属性)实现当容器尺寸发生变化时,内容自适应调整。
可以访问[布局约束](../../reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解aspectRatio属性的详细信息。
## 示例:
为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。
![zh-cn_image_0000001245614634](figures/zh-cn_image_0000001245614634.gif)
```ts
@Entry
@Component
struct ScaleCapabilitySample {
@State width: number = 400;
@State height: number = 400;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.width, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.width = value;
})
.position({ x: '20%', y: '80%' })
Slider({ value: this.height, min: 100, max: 400, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.height(50)
.onChange((value: number) => {
this.height = value;
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Flex({ justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center }) {
Column() {
Image($r("app.media.illustrator")).width('100%').height('100%')
}
.aspectRatio(1) // 固定宽高比
.border({ width: 2, color: "#66F1CCB8"}) // 边框,仅用于展示效果
}
.backgroundColor("#FFFFFF")
.height(this.width)
.width(this.height)
this.slider()
}.width('100%')
.height('100%')
.backgroundColor("#F1F3F5")
}
}
```
# 拉伸能力
拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。
拉伸能力通常通过Flex布局的flexGrow和flexShrink属性实现,详见[Flex布局](../../reference/arkui-ts/ts-universal-attributes-flex-layout.md)
- flexGrow:仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。
- flexShrink:仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。
特别的,当开发者期望将父容器的剩余空间全部分配给某空白区域时,也可以通过Blank组件实现。注意仅当父组件为Row\Column\Flex组件时,Blank组件才会生效,详见[Blank组件](../../reference/arkui-ts/ts-basic-components-blank.md)
## 示例1:
本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成。
中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。
两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。
因此父容器的基准尺寸是700vp(150vp+400vp+150vp)。
当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。
当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。
![zh-cn_image_0000001245613530](figures/zh-cn_image_0000001245613530.gif)
```ts
@Entry
@Component
struct FlexibleCapabilitySample1 {
@State width: number = 402;
// 底部滑块,可以通过拖拽滑块改变容器尺寸。
@Builder slider() {
Slider({ value: this.width, min: 402, max: 1000, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.width = value;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Flex({ direction: FlexDirection.Row, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
// 通过flexGrow和flexShink属性,将多余的空间全部分配给图片,将不足的控件全部分配给两侧空白区域。
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
Image($r("app.media.illustrator")).width(400).height(400)
.objectFit(ImageFit.Contain)
.backgroundColor("#66F1CCB8")
.flexGrow(1).flexShrink(0)
Row().width(150).height(400).backgroundColor('#FFFFFF')
.flexGrow(0).flexShrink(1)
}.width(this.width)
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
## 示例2:
文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。
![zh-cn_image_0000001266042114](figures/zh-cn_image_0000001266042114.gif)
```ts
@Entry
@Component
struct FlexibleCapabilitySample2 {
@State rate: number = 0.8;
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 30, max: 80, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '80%' })
}
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center,
alignItems: ItemAlign.Center }) {
Column() {
Row() {
Text('飞行模式')
.fontSize(16)
.width(135)
.height(22)
.fontWeight(FontWeight.Medium)
.lineHeight(22)
Blank() // 通过Blank组件实现拉伸能力
Toggle({ type: ToggleType.Switch })
.width(36)
.height(20)
}
.height(55)
.borderRadius(12)
.padding({ left: 13, right: 13 })
.backgroundColor('#FFFFFF')
.width(this.rate * 100 + '%')
}
this.slider()
}.width('100%').height('100%').backgroundColor('#F1F3F5')
}
}
```
# 折行能力
折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。
折行能力通过使用 **Flex折行布局** (将warp属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。
可以访问[Flex组件](../../reference/arkui-ts/ts-container-flex.md),了解Flex组件的详细用法。
## 示例:
父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。
![zh-cn_image_0000001292215677](figures/zh-cn_image_0000001292215677.gif)
```ts
@Entry
@Component
struct WrapCapabilitySample {
@State rate: number = 0.7;
const imageList: Resource [] = [
$r('app.media.flexWrap1'),
$r('app.media.flexWrap2'),
$r('app.media.flexWrap3'),
$r('app.media.flexWrap4'),
$r('app.media.flexWrap5'),
$r('app.media.flexWrap6')
];
// 底部滑块,可以通过拖拽滑块改变容器尺寸
@Builder slider() {
Slider({ value: this.rate * 100, min: 50, max: 70, style: SliderStyle.OutSet })
.blockColor(Color.White)
.width('60%')
.onChange((value: number) => {
this.rate = value / 100;
})
.position({ x: '20%', y: '87%' })
}
build() {
Flex({ justifyContent: FlexAlign.Center, direction: FlexDirection.Column }) {
Column() {
// 通过Flex组件warp参数实现自适应折行
Flex({
direction: FlexDirection.Row,
alignItems: ItemAlign.Center,
justifyContent: FlexAlign.Center,
wrap: FlexWrap.Wrap
}) {
ForEach(this.imageList, (item) => {
Image(item).width(183).height(138).padding(10)
})
}
.backgroundColor('#FFFFFF')
.padding(20)
.width(this.rate * 100 + '%')
.borderRadius(16)
}
.width('100%')
this.slider()
}.width('100%')
.height('100%')
.backgroundColor('#F1F3F5')
}
}
```
# 应用市场首页
本小节将以应用市场首页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AppMarket)中开源,读者可以根据需要自行下载源码并运行及查看效果。
## 页面设计
一个典型的应用市场首页的UX设计如下所示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001328579522](figures/zh-cn_image_0000001328579522.png) | ![zh-cn_image_0000001328259918](figures/zh-cn_image_0000001328259918.png) | ![zh-cn_image_0000001379179861](figures/zh-cn_image_0000001379179861.png) |
观察应用市场首页的页面设计,不同断点下的页面设计有较多相似的地方。
据此,我们可以将页面分拆为多个组成部分。
1. 底部/侧边导航栏
2. 标题栏与搜索栏
3. 运营横幅
4. 快捷入口
5. 精品应用
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001379299533](figures/zh-cn_image_0000001379299533.png) | ![zh-cn_image_0000001328259922](figures/zh-cn_image_0000001328259922.png) | ![zh-cn_image_0000001379179865](figures/zh-cn_image_0000001379179865.png) |
接下来我们逐一分析各部分的实现。
## 底部/侧边导航栏
在sm和md断点下,导航栏在底部;在lg断点下,导航栏在左侧。可以通过[Tab组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)的barPosition和vertical属性控制TabBar的位置,同时还可以通过barWidth和barHeight属性控制TabBar的尺寸。
```
@Entry
@Component
struct Index {
...
build() {
// 设置TabBar在主轴方向起始或结尾位置
Tabs({ barPosition: this.currentBreakpoint === "lg" ? BarPosition.Start : BarPosition.End }) {
// 首页
TabContent() {
Home()
}.tabBar(this.tabItem1)
TabContent() {}.tabBar(this.tabItem2)
TabContent() {}.tabBar(this.tabItem3)
TabContent() {}.tabBar(this.tabItem4)
TabContent() {}.tabBar(this.tabItem5)
}
.backgroundColor('#F1F3F5')
.barMode(BarMode.Fixed)
.barWidth(this.currentBreakpoint === "lg" ? 96 : '100%')
.barHeight(this.currentBreakpoint === "lg" ? '60%' : 56)
// 设置TabBar放置在水平或垂直方向
.vertical(this.currentBreakpoint === "lg")
}
}
```
另外在sm及lg断点下,TabBar中各个Item的图标和文字是按照垂直方向排布的,在md断点下,TabBar中各个Item的图标和文字是按照水平方向排布的。
```
@Component
export default struct TabBarItem {
...
build() {
if (this.currentBreakpoint !== 'md' ) {
// sm及lg断点下,tabBarItem中的图标和文字垂直排布
Column() {
...
}.justifyContent(FlexAlign.Center).height('100%').width('100%')
} else {
// md断点下,tabBarItem中的图标和文字水平排布
Row() {
....
}.justifyContent(FlexAlign.Center).height('100%').width('100%')
}
}
}
```
## 标题栏与搜索栏
标题栏和搜索栏,在sm和md断点下分两行显示,在lg断点下单行显示,可以通过栅格实现。在sm和md断点下,标题栏和搜索栏占满12列,此时会自动换行显示。在lg断点下,标题栏占8列而搜索栏占4列,此时标题栏和搜索栏在同一行中显示。
| | sm/md | lg |
| -------- | -------- | -------- |
| 效果图 | ![zh-cn_image_0000001379385785](figures/zh-cn_image_0000001379385785.png) | ![zh-cn_image_0000001379464977](figures/zh-cn_image_0000001379464977.jpg) |
| 栅格布局图 | ![zh-cn_image_0000001379464981](figures/zh-cn_image_0000001379464981.png) | ![zh-cn_image_0000001328745102](figures/zh-cn_image_0000001328745102.png) |
```
@Component
export default struct IndexHeader {
...
build() {
// 借助栅格实现标题栏和搜索栏在不同断点下的不同布局效果。
GridRow() {
GridCol({ span: { xs: 12, lg: 8 } }) {
this.titleBar()
}
GridCol({ span: { xs: 12, lg: 4 } }) {
this.searchBar()
}
}
.width('100%')
}
}
```
## 运营横幅
不同断点下的运营横幅,sm断点下显示一张图片,md断点下显示两张图片,lg断点下显示三张图片。可以通过[Swiper组件的displayCount属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)实现目标效果。
```
@Component
export default struct IndexSwiper {
...
@Builder swiperItem(imageSrc) {
Image(imageSrc)
.width('100%')
.aspectRatio(2.5)
.objectFit(ImageFit.Fill)
}
build() {
Swiper() {
this.swiperItem($r('app.media.ic_public_swiper1'))
this.swiperItem($r('app.media.ic_public_swiper2'))
this.swiperItem($r('app.media.ic_public_swiper3'))
...
}
.autoPlay(true)
.indicator(false)
.itemSpace(10)
// 配置不同断点下运行横幅中展示的图片数量
.displayCount(this.currentBreakpoint === 'sm' ? 1 : (this.currentBreakpoint === 'md' ? 2 : 3))
.width('100%')
.padding({ left: 12, right: 12, bottom: 16, top: 16 })
}
}
```
## 快捷入口
在不同的断点下,快捷入口的5个图标始终均匀排布,这是典型的均分能力使用场景。
```
@Component
@Component
export default struct IndexEntrance {
build() {
// 将justifyContent参数配置为FlexAlign.SpaceEvenly实现均分布局
Row() {
ForEach(entranceIcons, (icon: AllIcons) => {
// 各快捷入口的图标及名称
Column() { ... }
})
}
.width('100%')
.height(64)
.justifyContent(FlexAlign.SpaceEvenly)
.padding({ left: 12, right: 12 })
}
}
```
## 精品应用
随着可用显示区域的增加,精品应用中显示的图标数量也不断增加,这是典型的延伸能力使用场景。精品游戏的实现与精品应用类似,不再展开分析。
```
@Component
@Component
export default struct IndexApps {
...
build() {
Column() {
this.appListHeader()
// 借助List组件能力,实现延伸能力场景
List({ space: this.currentBreakpoint === 'lg' ? 44 : 20}) {
LazyForEach(new MyAppSource(this.apps), app => {
ListItem() {
// 每个应用的图标、名称及安装按钮
this.appListItem(app)
}
}, app => app.id)
}
.width('100%')
.height(this.currentBreakpoint === 'lg' ? 140 : 120)
.listDirection(Axis.Horizontal)
}
.width('100%')
.height(this.currentBreakpoint === 'lg' ? 188 : 164)
.padding({ bottom: 8, left: 12, right: 12 })
}
}
```
## 运行效果
将上述各页面主要部分组合在一起后,即可完成整体页面开发。
```
@Component
struct IndexContent {
...
build() {
List() {
// 运营横幅
ListItem() {
IndexSwiper()
}
// 快捷入口
ListItem() {
IndexEntrance()
}
// 精品应用
ListItem() {
IndexApps({ title: $r('app.string.boutique_application'), apps: appList })
}
// 精品游戏
ListItem() {
IndexApps({ title: $r('app.string.boutique_game'), apps: gameList })
}
}
.width("100%")
}
}
@Component
export default struct Home {
...
build() {
Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Start, alignItems: ItemAlign.Start }) {
// 标题栏和搜索栏
IndexHeader()
// 运营横幅、快捷入口、精品应用、精品游戏等
IndexContent()
}
.height('100%')
.backgroundColor("#F1F3F5")
}
}
```
本页面的实际运行效果如下图所示。
| sm | md | lg |
| -------- | -------- | -------- |
| ![zh-cn_image_0000001334345550](figures/zh-cn_image_0000001334345550.jpg) | ![zh-cn_image_0000001385105477](figures/zh-cn_image_0000001385105477.jpg) | ![zh-cn_image_0000001384985569](figures/zh-cn_image_0000001384985569.jpg) |
<!--no_check-->
\ No newline at end of file
# 应用架构设计
- **[应用导航结构设计要求](navigation-design.md)**
- **[应用页面结构设计](page-design.md)**
\ No newline at end of file
# 桌面应用
[桌面](https://gitee.com/openharmony/applications_launcher)是OpenHarmony中预置的系统应用,它是系统人机交互的首要入口。
## 应用功能
桌面提供了如下功能:
- 万能卡片:包括卡片的呼出和关闭、卡片管理、卡片拖动、卡片移除等。
- 任务中心:展示后台运行任务的快照。
- 大文件夹:包括大文件基础展示、将应用拖入及移出大文件夹等。
- 应用中心:展示全量桌面应用列表。
- 图标管理:图标显示、长按图标显示菜单列表等。
- 布局管理:对不同的设备、横竖屏、分辨率等做布局自适应。
- 桌面设置:设置桌面布局方案。
- 手势导航:允许用户用手势导航替代传统的三键导航。
- 应用启动:启动应用、应用启动动效等。
- 键鼠适配:支持鼠标及键盘。
- 快捷栏(Smart Dock):底部快捷栏,显示常用应用列表、支持添加应用快捷方式及删除等。
部分功能场景设计图如下所示。
| 功能点 | 默认设备 | 平板 |
| -------- | -------- | -------- |
| 万能卡片 | ![zh-cn_image_0000001267293008](figures/zh-cn_image_0000001267293008.jpg) | ![zh-cn_image_0000001267932928](figures/zh-cn_image_0000001267932928.jpg) |
| 任务中心 | ![zh-cn_image_0000001315932969](figures/zh-cn_image_0000001315932969.jpg) | ![zh-cn_image_0000001316932917](figures/zh-cn_image_0000001316932917.jpg) |
| 快捷栏 | ![zh-cn_image_0000001315453085](figures/zh-cn_image_0000001315453085.jpg) | ![zh-cn_image_0000001315732933](figures/zh-cn_image_0000001315732933.jpg) |
| 大文件夹 | ![zh-cn_image_0000001267532988](figures/zh-cn_image_0000001267532988.jpg) | ![zh-cn_image_0000001266893124](figures/zh-cn_image_0000001266893124.jpg) |
| 应用中心 | NA | ![zh-cn_image_0000001267293016](figures/zh-cn_image_0000001267293016.jpg) |
| 键鼠适配 | NA | ![zh-cn_image_0000001267932936](figures/zh-cn_image_0000001267932936.jpg) |
| 桌面设置 | ![zh-cn_image_0000001315932977](figures/zh-cn_image_0000001315932977.jpg) | ![zh-cn_image_0000001316932929](figures/zh-cn_image_0000001316932929.jpg) |
## 部署模型
如前所述,为保证最佳的体验效果,桌面应用根据默认设备和平板的特性,做了深入定制。
- 不同设备桌面应用的特性规格有差异。
- 平板有应用中心功能,平板通过快捷栏任务中心图标进入任务中心,才能看到全量应用。默认设备直接在桌面上显示全量应用,没有应用中心功能。
- 默认设备不需要适配键鼠输入。
- 同一特性,在不同设备上页面跳转逻辑有差异。
默认设备和平板的万能卡片管理页面完全不同,默认设备上是跳转到新的页面进行卡片管理操作,而平板上是直接在原有页面上弹出Dailog窗口进行卡片管理操作。
因此,桌面最终选择了[部署模型B](introduction.md#部署模型),即默认设备和平板上部署不同的HAP包。
## 工程结构
```
/applications
├── common # 公共模块目录
│ └── src
│ └── main
│ └── ets
│ └── default
│ ├── base # 公共presenter层代码目录
│ ├── bean # 公共数据对象
│ ├── cache # 缓存目录
│ ├── configs # 应用配置对象目录
│ ├── constants # 应用常量对象目录
│ ├── manager # manager代码目录
│ ├── model # Model层代码目录
│ ├── settings # settings配置项
│ ├── uicomponents # 自定义组件目录
│ └── utils # 工具类代码目录
├── feature # feature层模块目录
│ ├── appcenter # 应用中心模块目录
│ ├── bigfolder # 大文件夹模块目录
│ ├── form # 卡片模块目录
│ ├── gesturenavigation # 桌面设置模块目录
│ ├── launcherlayout # 桌面布局计算模块目录
│ ├── pagedesktop # 桌面设置模块目录
│ ├── recents # 最近任务模块目录
│ ├── settings # 桌面设置模块目录
│ └── smartdock # dock栏模块目录
└── product # 产品层模块目录
├── pad # 平板目录
└── phone # 默认设备目录
```
桌面应用在开发阶段,采用了三层工程结构。默认设备和平板共用feature和common目录中的代码,仅在product目录中各自有部分独立代码。
- 业务形态层(product)
包含不同产品形态的桌面。含桌面窗口、个性化业务、组件的配置以及个性化资源包。不同产品形态,编译出不同的Launcher的HAP包,各产品按需部署。
- 公共特性层(feature)
抽象的公共特性组件集合,可以被product层不同形态的桌面所引用,并且在product层上做一些定制化的配置。
- 功能能力层(common)
基础能力集,每个桌面形态都必须要依赖的模块。该层不可被分割,方便后续架构拓展和演进。
## 总结
本小节主要仅从工程结构角度介绍桌面应用,读者如果对其具体实现感兴趣,可以访问[桌面应用开源代码仓](https://gitee.com/openharmony/applications_launcher)了解详情。桌面应用在默认设备和平板上功能有较大差异,因此最终选择了部署模型B。虽然在默认设备和平板上是不同的安装包,但二者依然公用了非常多的代码。经统计,**共用代码占比在90%左右**。在后续拓展其它设备类型时,依然可以使用此部分公共代码。这既可以提高多设备场景开发效率,同时也可以降低后期的维护成本。
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
**基于触控的交互** **基于触控的交互**
很多设备都拥有支持多点触控的屏幕,允许用户使用手指和/或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。 很多设备的屏幕都支持多点触控,允许用户通过手指或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。
以下是基础的手势操作: 以下是基础的手势操作:
......
# 自适应布局 # 自适应布局
自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。 自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。
## 自适应拉伸 ## 自适应拉伸
某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。 某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。
左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。 左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。
![zh-cn_image_0000001258762686](figures/zh-cn_image_0000001258762686.gif) ![拉伸能力](figures/拉伸能力.gif)
均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。 均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。
![zh-cn_image_0000001291556325](figures/zh-cn_image_0000001291556325.gif) ![均分能力](figures/均分能力.gif)
自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。 自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。
当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。 当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。
![zh-cn_image_0000001245276368](figures/zh-cn_image_0000001245276368.png) ![拉伸注意场景](figures/拉伸注意场景.png)
## 自适应缩放 ## 自适应缩放
组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。 组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。
完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。 完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。
![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif) ![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif)
占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。 占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。
![zh-cn_image_0000001245116688](figures/zh-cn_image_0000001245116688.gif) ![缩放案例](figures/缩放案例.gif)
自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。 自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。
不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。 不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。
![zh-cn_image_0000001292842113](figures/zh-cn_image_0000001292842113.gif) ![4.3-2](figures/4.3-2.png)
## 自适应延伸 ## 自适应延伸
组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。 组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。
同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。 同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。
![zh-cn_image_0000001291556369](figures/zh-cn_image_0000001291556369.gif) ![延长能力](figures/延长能力.gif)
不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。 不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。
![zh-cn_image_0000001245276416](figures/zh-cn_image_0000001245276416.gif) ![隐藏能力](figures/隐藏能力.gif)
自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。 自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。
注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。 注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。
## 自适应折行 ## 自适应折行
定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。 定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。
例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。 例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。
![zh-cn_image_0000001291675805](figures/zh-cn_image_0000001291675805.png) ![折行案例分镜](figures/折行案例分镜.png)
自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。 自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。
自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout-intro.md)”。 自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout.md)”相关介绍。
# 设计自检表 # 设计自检表
设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。 设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。
自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。 自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。
请参考以下表格范围内提出的要求对应用进行检查。
请参考以下表格范围内提出的要求对应用进行检查。
| **类型** | **条目** | **说明** |
| -------- | ------------------ | ------------------------------------------------------------ | | **类型** | **条目** | **说明** |
| 应用架构 | 导航结构 | 保证同一应用/服务在各设备上导航结构一致。 | | -------- | ------------------ | ------------------------------------------------------------ |
| | 界面框架 | 尽量使用推荐的常用界面架构,以更好达到一多效果。 | | 应用架构 | 导航结构 | 在各设备上页面导航结构保持一致(同时出多个设备的UX设计)。 |
| 布局 | 自适应布局 | 关注布局标注是否逻辑合理,是否具备自适应能力。保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形地正常显示。 | | 布局 | 拉通设计 | 拉通各设备的布局设计,保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形/不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)/无大图大字体地正常显示。 |
| | 响应式布局 | 关注布局是否更有效利用屏幕控件,是否具备响应式能力。保证在不同尺寸和分辨率的设备上不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)。 | | | 响应式设计 | 栅格布局只能占N列以及N列内部的Gutter,不包含N列两侧的Gutter。 |
| | 页面结构 | 尽量使用推荐的常用页面结构,以更好达到一多效果。 | | | 响应式设计 | 明确标注使用什么类型的栅格、给出在不同断点下栅格三要素取值。 |
| | 页面结构优化 | 在通用能力不适用业务诉求时,进行页面特殊优化,保证在具体设备上的使用体验。 | | | 响应式设计 | 按容器去对齐栅格,而不是内部子元素对齐栅格。 |
| 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 | | | 响应式设计 | 栅格除了页面布局设计外,在做局部栅格设计时,需要通过明显方式如颜色等进行标注区分,避免混淆。 |
| | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 | | | 响应式设计 | 禁止出现标注了栅格但实际没有通过栅格进行布局设计,避免混淆。 |
| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 | | | 自适应设计 | 非栅格设计场景下,明确标注自适应布局能力。自适应布局能力有:拉伸、均分、占比、缩放、延伸、隐藏、折行。 |
| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 | | 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 |
| | 字体 | 尽量使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 | | | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 |
| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 |
| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 |
| | 字体 | 使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 |
| 多态控件 | 支持常用的控件状态 | 确保控件不同状态下的视觉效果没有缺失。控件的常用状态有:正常态、不可用态、点击态、获焦态、激活态、悬停态。 | | 多态控件 | 支持常用的控件状态 | 确保控件不同状态下的视觉效果没有缺失。控件的常用状态有:正常态、不可用态、点击态、获焦态、激活态、悬停态。 |
\ No newline at end of file
# 设计交付
## 概述
为了将UX设计详尽准确地实现并传递给开发者,设计师需向开发者提供必要的设计交付件,包括但不限于:应用规格说明、交互流程、视觉效果、视觉标注、视觉规格说明、切图资源、动效参数资源、音效资源等内容。
面向多设备多尺寸的应用UX设计交付件,以完整说明界面布局与视觉设计为主要目的,至少应包含:效果图、标注图、规格说明和切图资源。
下面将分别介绍不同交付内容的用途与规范。
![4.8-交付4件套](figures/4.8-交付4件套.png)
## 效果图
效果图是表达UX设计的关键内容,用于直观呈现目标体验的静态效果,并作为开发者与测试工程师的实现与验收依据。效果图一般为jpg或png格式。
在优秀的设计交付件中,针对不同前置条件下,各交互流程所途经的每个界面都应匹配效果图。对于大量重复使用的组件元素,如弹窗和即时反馈,亦可配合规格统一说明,不做过多重复设计。
在多设备设计中,为了清晰表达设计效果,设计师仍需要针对不同尺寸的关键界面提供符合规范的效果图。关键界面包括且不限于:
- 应用的首页
- 可以从首页直接进入的各二级界面
- 核心使用流程途经的各界面
- 能体现多数界面的自适应与响应式规格的典型界面
不同尺寸的效果图,至少应包含小设备、中设备、大设备。根据业务涉及的设备特点,可补充超小尺寸效果,及不同设备的横竖屏效果,提前充分验证并优化UX设计体现的差异性、一致性、灵活性、兼容性。
对应不同设备效果图的设计画板尺寸推荐如下:
| 设备类型 | 屏幕宽度 | 画板尺寸(vp) |
| -------- | -------- | -------- |
| 超小设备 | [0,&nbsp;320) | 240\*320 |
| 小设备 | [320,&nbsp;520) | 360\*780 |
| 中设备 | [520,&nbsp;840) | 677\*763 |
| 大设备 | [840,&nbsp;+) | 1280\*800 |
多设备效果示意图
![4.8-效果示意图](figures/4.8-效果示意图.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 画板尺寸为不同宽度断点下的典型设备屏幕尺寸,可根据业务具体针对的设备选择其他画板尺寸。
>
> - 画板尺寸以vp为单位提供,根据实际设计所需精度,可统一把设计文档中所有画板设置为1倍或多倍的px尺寸。
>
> - 当效果图需要展示一屏以上的内容,如列表内容较长时,建议保持宽度不变并增加画板高度以容纳更多内容。
## 标注图
标注图是向开发者传递界面上每个元素详细属性,以指导代码完整实现UX设计的图像化文档。界面元素的属性包括:色彩、尺寸、字体、圆角、间距、阴影、模糊、缩放、所用的组件、自适应布局、响应式布局等。标注图一般为jpg或png格式。
在优秀的设计交付件中,不同类型属性的标注文本大小一致、色彩不一、互不重叠,并与效果图内容在视觉上良好区隔。标注图数量与关键界面效果图一一对应,如遇到较复杂的界面,为了更清晰说明规格,也有多张标注图对应一张效果图的情况。
随着设计与开发工具的演进,一些业界工具支持界面元素属性的自动识别并创建标注,也可导出支持动态展示标注的效果图文档,一般为html格式。OpenHarmony应用的设计交付同样可以借助这些工具作为标注图的补充内容,但必选的分层参数仍需设计师专门确认并手动完成标注。
除了尺寸、间距等强依赖于业务具体设计的参数,色彩、字体、圆角、阴影、模糊等属性应尽可能使用分层参数完成标注。
标注示意图
![4.8-标注图](figures/4.8-标注图.png)
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> - 如遇到分层参数覆盖不到的属性值,可按照具体设计效果标注。此时必须详细考虑不同场景下该元素的效果。
## 规格说明
规格说明是一份专门编写的文档,用于更完整清晰地说明界面间的通用元素与变化规则,一般为pdf格式。规格说明不是UX设计交付件中的必选项,但它能帮助设计师节省很多重复性工作,帮助开发者快速理解UX设计规格,在面向多设备的应用设计交付中非常推荐。
在多设备设计中,规格说明常用于并排展示同一界面在不同尺寸下的效果,并说明栅格变化规则。
一多规范栅格图
![4.8-栅格标注](figures/4.8-栅格标注.png)
## 切图资源
包含在设计效果中的素材,如图标、图片、序列帧等,应根据实际需要输出为合适的格式提供开发者置入界面内。
为了更好在多设备上根据设备dpi展示清晰的图像,一分优秀的应用应含有多套同名的切图资源,它们分别存放在mdpi、ldpi、xldpi、xxldpi的文件夹目录下,最终会存放到应用资源包的同名路径中。
多套同名切图文件夹示意图
![4.8-切图资源对应文件夹](figures/4.8-切图资源对应文件夹.png)
图标资源可以是png、jpg、webp、svg等格式。推荐在多设备设计中使用svg图标资源,因为能充分利用矢量图片体积较小、可以自由缩放且不出现锯齿、可根据色彩参数实时赋色的特点,仅用一套资源即可满足复杂场景的UX规范。如使用其他位图格式如png、jpg、webp,则需分别交付各dpi下的切图资源,以达到边缘像素清晰的体验。
图片资源可以是png、jpg、webp等格式。与图标资源类似,一般应提供各dpi下的图片资源。在不同dpi下对边缘像素要求不高的图片如背景图,则推荐按照更高dpi提供一张资源复用到各dpi,以减少应用包大小。
在多设备设计中,图片也可根据设计效果,在不同宽度断点使用同一个资源,或分别交付:
- 当图片所在组件接口提供的缩放显示机制满足UX设计效果,可以用同一个资源
- 当图片所在组件接口提供的缩放显示机制不满足、且不可通过简单的自定义规则实现UX效果,则推荐使用不同资源
夜晚单张适配多设备宽度示意图
![4.8-夜晚单张适配多设备](figures/4.8-夜晚单张适配多设备.png)
晴天多张适配多设备宽度示意图
![4.8-晴天多张适配](figures/4.8-晴天多张适配.png)
# 栅格系统 # 栅格系统
栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。 栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。
通过栅格系统进行布局,可以更好达到多设备下布局的一致性。 通过栅格系统进行布局,可以更好达到多设备下布局的一致性。
![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png) ![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png)
Margin、Gutter的大小、Column的数量均可自定义,界面内容跟据Column的边缘定位。通过采用不同数值调整内容信息量和紧密程度,一般推荐使用4或8的倍数。例如Margin 32vp、Gutter 16vp、Column数量为4,或Margin 40vp、Gutter 24vp、Column数量为8。 Margin、Gutter的大小、Column的数量均可自定义,界面内容跟据Column的边缘定位。通过采用不同数值调整内容信息量和紧密程度,一般推荐使用4或8的倍数。例如Margin 32vp、Gutter 16vp、Column数量为4,或Margin 40vp、Gutter 24vp、Column数量为8。
![zh-cn_image_0000001305734113](figures/zh-cn_image_0000001305734113.png) ![栅格系统例](figures/栅格系统例.png)
栅格系统对应OpenHarmony系统提供的布局能力中的栅格布局,详见本文 “[栅格布局](responsive-layout.md#栅格布局)”相关介绍。
# 交互事件归一 # 交互事件归一
本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。** 本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。**
![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png) ![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png)
## 打开/切换对象 ## 打开/切换对象
用户通过点击某个元素触发功能、访问新页面、或改变自身状态。 用户通过点击某个元素触发功能、访问新页面、或改变自身状态。
| **输入方式** | **交互行为** | **示意** | | **输入方式** | **交互行为** | **示意** |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) | | 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) |
| 鼠标 | 左键单击&nbsp;/&nbsp;左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) | | 鼠标 | 左键单击&nbsp;/&nbsp;左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) |
| 触摸板 | 单指单击&nbsp;/&nbsp;单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) | | 触摸板 | 单指单击&nbsp;/&nbsp;单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) |
| 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) | | 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) |
一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。 一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。
在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。 在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。
## 显示菜单 ## 显示菜单
某个元素上显示弹出菜单或快捷方式菜单。 某个元素上显示弹出菜单或快捷方式菜单。
![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg) ![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg)
| **输入方式** | **交互行为** | | **输入方式** | **交互行为** |
| -------- | -------- | | -------- | -------- |
| 触屏 | 单指长按 | | 触屏 | 单指长按 |
| 鼠标 | 右键单击(与PC一致)/&nbsp;左键长按(保留触屏习惯) | | 鼠标 | 右键单击(与PC一致)/&nbsp;左键长按(保留触屏习惯) |
| 触摸板 | 双指轻单击/重单击(与PC一致)/&nbsp;单指重长按(保留触屏习惯) | | 触摸板 | 双指轻单击/重单击(与PC一致)/&nbsp;单指重长按(保留触屏习惯) |
| 键盘 | (无通用操作) | | 键盘 | (无通用操作) |
这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。 这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。
凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。 凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。
## 拖拽对象 ## 拖拽对象
直接指向某个元素并移动到界面其他位置 直接指向某个元素并移动到界面其他位置
![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png) ![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png)
| **输入方式** | **交互行为** | | **输入方式** | **交互行为** |
| -------- | -------- | | -------- | -------- |
| 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 | | 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 |
| 鼠标&nbsp;/&nbsp;触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 | | 鼠标&nbsp;/&nbsp;触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 |
| 键盘 | (无通用操作) | | 键盘 | (无通用操作) |
# 布局基础运用案例 # 布局基础运用案例
## 平级导航的复合网格视图 ## 平级导航的复合网格视图
平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 平级导航的复合网格视图常出现在同时展示多种不同内容的界面。
例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。 例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。
![zh-cn_image_0000001317088945](figures/zh-cn_image_0000001317088945.png) ![一多-布局1](figures/一多-布局1.png)
- 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。 - 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。
- 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。 - 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。
- 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。 - 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。
- 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。 - 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。
在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。 在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。
![zh-cn_image_0000001317328797](figures/zh-cn_image_0000001317328797.png) ![一多-布局2](figures/一多-布局2.png)
当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。 当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。
![zh-cn_image_0000001268448854](figures/zh-cn_image_0000001268448854.png) ![一多-布局3](figures/一多-布局3.png)
## 层级导航的列表视图 ## 层级导航的列表视图
层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。 层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。
例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。 例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。
![zh-cn_image_0000001268128998](figures/zh-cn_image_0000001268128998.png) ![布局基础案例-层级导航-设置](figures/布局基础案例-层级导航-设置.png)
在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。 在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。
## 专辑详情页面 ## 专辑详情页面
专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。 专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。
例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。 例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。
- 标题栏:采用自适应拉伸。 - 标题栏:采用自适应拉伸。
- 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。 - 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。
- 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。 - 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。
- 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。 - 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。
- 播放栏:固定在界面底部,保持左右拉伸即可。 - 播放栏:固定在界面底部,保持左右拉伸即可。
![zh-cn_image_0000001268288870](figures/zh-cn_image_0000001268288870.png) ![页面布局-布局基础案例-歌单详情页面布局能力360-800vp](figures/页面布局-布局基础案例-歌单详情页面布局能力360-800vp.png)
在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。 在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。
歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。 歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。
![zh-cn_image_0000001268608782](figures/zh-cn_image_0000001268608782.png) ![页面布局-布局基础案例-歌单详情页面布局能力800-1280vp](figures/页面布局-布局基础案例-歌单详情页面布局能力800-1280vp.png)
当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。 当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。
![zh-cn_image_0000001317208833](figures/zh-cn_image_0000001317208833.png) ![页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp](figures/页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp.png)
# 多态控件 # 多态控件
为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。 为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。
![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png) ![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png)
多态控件应该具备以下特点: 多态控件应该具备以下特点:
- 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。 - 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。
- 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。 - 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。
- 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。 - 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。
## 控件的状态 ## 控件的状态
- 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。 - 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。
- 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。 - 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。
常见的状态类型: 常见的状态类型:
| | | | | | | |
| -------- | -------- | -------- | | -------- | -------- | -------- |
| ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)<br/>**正常态**<br/>表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)<br/>**不可用态**<br/>表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)<br/>**点击态**<br/>表明当前控件当前处于点击状态。<br/>操作:手指或鼠标按下且未释放。 | | ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)<br/>**正常态**<br/>表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)<br/>**不可用态**<br/>表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)<br/>**点击态**<br/>表明当前控件当前处于点击状态。<br/>操作:手指或鼠标按下且未释放。 |
| ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)<br/>**获焦态**<br/>表明当前控件处于焦点状态。操作:<br/>-&nbsp;键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。<br/>-&nbsp;通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)<br/>**激活态**<br/>表明当前控件处于激活的状态。用于有多个元素可获焦的控件<br/>操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)<br/>**悬停态**<br/>表明当前控件处于鼠标悬停的状态。<br/>操作:将鼠标悬停在控件之上。 | | ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)<br/>**获焦态**<br/>表明当前控件处于焦点状态。操作:<br/>-&nbsp;键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。<br/>-&nbsp;通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)<br/>**激活态**<br/>表明当前控件处于激活的状态。用于有多个元素可获焦的控件<br/>操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)<br/>**悬停态**<br/>表明当前控件处于鼠标悬停的状态。<br/>操作:将鼠标悬停在控件之上。 |
## 弹出框
弹出框是一种模态窗口,在弹出框消失之前,用户无法操作其他界面内容,干扰性比较强。通常用来展示用户当前需要的或用户必须关注的信息或操作,其他情况不建议使用弹出框,可考虑通知等其他非模态窗口。 弹出框的内容通常是不同控件进行组合布局。例如文本(可带格式,如缩进、链接、粗体等)、列表、输入框、网格、图标或图片等,常用于选择或确认信息。
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
**兼容性** **兼容性**
在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可用、使用困难的问题。 在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可用、使用困难的问题。
## 设计要点 ## 设计要点
...@@ -35,9 +35,9 @@ ...@@ -35,9 +35,9 @@
例如:默认设备上的底Tab的结构,在Pad上一般使用侧边Tab来代替,在大屏上则是顶部Tab。 例如:默认设备上的底Tab的结构,在Pad上一般使用侧边Tab来代替,在大屏上则是顶部Tab。
![zh-cn_image_0000001317325609](figures/zh-cn_image_0000001317325609.png) ![一多-1-1](figures/一多-1-1.png)
更多应用架构的设计内容,详见:[应用导航结构设计](navigation-design.md)[应用页面结构设计](page-design.md) 更多应用架构的设计内容,详见:[应用架构](architecture-design.md)
### 响应式界面布局 ### 响应式界面布局
...@@ -48,31 +48,31 @@ OpenHarmony 提供了多种布局能力,开发者通过组合运用使内容 ...@@ -48,31 +48,31 @@ OpenHarmony 提供了多种布局能力,开发者通过组合运用使内容
例如:默认设备上的滚动banner,在其他设备上可进行延伸,平板上露出更多banner,大屏上完全显示两张。 例如:默认设备上的滚动banner,在其他设备上可进行延伸,平板上露出更多banner,大屏上完全显示两张。
![zh-cn_image_0000001317485573](figures/zh-cn_image_0000001317485573.png) ![一多-概述-界面布局-banner例图](figures/一多-概述-界面布局-banner例图.png)
在不同类型的设备上,界面的尺寸和比例更为多样,再加上使用上的差异,导致设计上更为复杂。为此,可以考虑使用分栏布局、重复布局、挪移布局、缩进布局,进一步解决内容的显示问题。 在不同类型的设备上,界面的尺寸和比例更为多样,再加上使用上的差异,导致设计上更为复杂。为此,可以考虑使用分栏布局、重复布局、挪移布局、缩进布局,进一步解决内容的显示问题。
例如:默认设备上上下排布的大图与列表,在长宽比例更大的设备上可挪移到左右展示。 例如:默认设备上上下排布的大图与列表,在长宽比例更大的设备上可挪移到左右展示。
![zh-cn_image_0000001268285678](figures/zh-cn_image_0000001268285678.png) ![概述-界面布局-歌单详情高保真](figures/概述-界面布局-歌单详情高保真.png)
更多界面布局的设计内容,详见:[界面布局](layout-design-intro.md) 更多界面布局的设计内容,详见:[界面布局](interface-layout-design.md)
### 交互归一 ### 交互归一
交互归一描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。通常情况下,系统已经做好了这些事情,开发者只需正确调用。如果您的操作比较特别,您需要考虑多端上的交互归一,以确保用户体验的一致。 交互归一描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。通常情况下,系统已经做好了这些事情,开发者只需正确调用。如果您的操作比较特别,您需要考虑多端上的交互归一,以确保用户体验的一致。
更多交互归一的设计内容,详见:[人机交互](interaction-basics.md) 更多交互归一的设计内容,详见:[人机交互](man-machine-interaction.md)
### 视觉参数化 ### 视觉参数化
通过参数,方便的调整各端的视觉,使得各端具备该设备特有的风格。在OpenHarmony中,边距、圆角、阴影、字体大小等,都可以通过参数来进行调整。 通过参数,方便的调整各端的视觉,使得各端具备该设备特有的风格。在OpenHarmony中,边距、圆角、阴影、字体大小等,都可以通过参数来进行调整。
![zh-cn_image_0000001317085757](figures/zh-cn_image_0000001317085757.png) ![画板copy](figures/画板copy.png)
更多视觉参数化的设计内容,详见:[视觉风格](visual-style-basics.md) 更多视觉参数化的设计内容,详见:[视觉风格](visual-style.md)
### 多态控件 ### 多态控件
...@@ -91,6 +91,6 @@ OpenHarmony默认提供支持多设备的控件,开发者可以直接使用并 ...@@ -91,6 +91,6 @@ OpenHarmony默认提供支持多设备的控件,开发者可以直接使用并
| **以触控为主** | **以键鼠操作为主** | | **以触控为主** | **以键鼠操作为主** |
| -------- | -------- | | -------- | -------- |
| 下拉刷新 | 界面上提供“刷新”图标或适配F5快捷键 | | 下拉刷新 | 界面上提供“刷新”图标或适配F5快捷键 |
| 滑动多选 | 鼠标&nbsp;框选 | | 滑动多选 | 鼠标框选 |
| 下拉关闭 | 界面上提供“关闭”图标 | | 下拉关闭 | 界面上提供“关闭”图标 |
| 长按浮起拖拽 | 鼠标直接拖拽 | | 长按浮起拖拽 | 鼠标直接拖拽 |
# 资源 # 资源
为方便UX设计师以及开发者使用[分层参数](visual-style-basics.md),本文特提供 [OpenHarmony_系统资源分层设计表_V1.0.xlsm](OpenHarmony_系统资源分层设计表_V1.0.xlsm)
为方便UX设计师以及开发者参考使用,本文特提供:
- [分层参数](visual-basics.md)的场景、id、参数详细对照表,[OpenHarmony_系统资源分层设计表_V1.0.xlsm](OpenHarmony_系统资源分层设计表_V1.0.xlsm)
- 符合规范的[设计交付件](design-delivery.md)样例,[OpenHarmony_天气应用UX设计交付件_V1.0.zip](OpenHarmony_天气应用UX设计交付件_V1.0.zip)
系统资源分层设计表列出了当前OpenHarmony中可用系统资源id及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。 系统资源分层设计表列出了当前OpenHarmony中可用系统资源id及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。
| 表格 | 简介 |
| ------------------ | ------------------------------------------------------------ | | 表格 | 简介 |
| 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 | | -------- | -------- |
| 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 | | 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 |
| 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 | | 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 |
| 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 | | 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 |
| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 | | 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 |
| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 |
| 不透明度数值速查表 | 用于将不透明度在**百分比表示形式****十六进制表示形式**之间快速转换的速查表。 | | 不透明度数值速查表 | 用于将不透明度在**百分比表示形式****十六进制表示形式**之间快速转换的速查表。 |
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** > ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
>
> - 推荐应用相关系统参数仅在应用开发场景中使用,卡片相关系统参数仅在卡片开发场景中使用。 > - 推荐应用相关系统参数仅在应用开发场景中使用,卡片相关系统参数仅在卡片开发场景中使用。
>
> - 同一系统参数在不同类型的设备上有不同的取值,当前仅提供了系统参数在默认设备上的取值,后续会针对不同设备类型做补充。 > - 同一系统参数在不同类型的设备上有不同的取值,当前仅提供了系统参数在默认设备上的取值,后续会针对不同设备类型做补充。
> - 颜色可以用“RGB”或“ARGB”形式表示,采用“RGB”表示的颜色,完全不透明;采用“ARGB”表示的颜色,其不透明度由“A”(Alpha通道)确定。如“#7FFF0000”代表不透明度为50%的红色,“#FFFF0000”和“#FF0000”都表示不透明度为100%(即完全不透明)的红色。 >
\ No newline at end of file > - 颜色可以用“RGB”或“ARGB”形式表示,采用“RGB”表示的颜色,完全不透明;采用“ARGB”表示的颜色,其不透明度由“A”(Alpha通道)确定。如“\#7FFF0000”代表不透明度为50%的红色,“\#FFFF0000”和“\#FF0000”都表示不透明度为100%(即完全不透明)的红色。
# 响应式布局 # 响应式布局
当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。 当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。
## 栅格断点系统 ## 栅格断点系统
根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。 根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。
![zh-cn_image_0000001305864477](figures/zh-cn_image_0000001305864477.png) ![删格](figures/删格.png)
栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。 栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。
随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。 随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。
## 缩进布局 ## 缩进布局
为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。 为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。
![zh-cn_image_0000001264774952](figures/zh-cn_image_0000001264774952.gif) ![缩进布局](figures/缩进布局.gif)
缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。 缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。
OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。 OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。
## 挪移布局 ## 挪移布局
利用屏幕的宽度优势,将原先的上下布局切换成左右布局。 利用屏幕的宽度优势,将原先的上下布局切换成左右布局。
例如,上下排布的插画和文字,横屏后左右排布。 例如,上下排布的插画和文字,横屏后左右排布。
![zh-cn_image_0000001264296340](figures/zh-cn_image_0000001264296340.gif) ![挪移布局](figures/挪移布局.gif)
挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。 挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。
## 重复布局 ## 重复布局
利用屏幕的宽度优势,将相同属性的组件横向并列排布。 利用屏幕的宽度优势,将相同属性的组件横向并列排布。
![zh-cn_image_0000001306203573](figures/zh-cn_image_0000001306203573.gif) ![重复布局](figures/重复布局.gif)
重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。 重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。
OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。 OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。
响应式布局对应OpenHarmony系统提供的布局能力中的[栅格断点系统](grid-breakpoint.md)[媒体查询](media-query.md),详见本文 “响应式布局”。 响应式布局对应OpenHarmony系统提供的布局能力中的栅格断点系统和媒体查询,详见本文 “[响应式布局](responsive-layout.md)”相关介绍。
# 一多能力的功能开发介绍 # 功能开发的一多能力介绍
应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。 应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。
我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。 我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。
应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载-&gt;应用安装-&gt;应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路: 应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载-&gt;应用安装-&gt;应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路:
1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。 1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。
2. 安装:有NFC能力的设备才允许安装该应用。 2. 安装:有NFC能力的设备才允许安装该应用。
3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。 3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。
所以,对应的解决方案就有: 所以,对应的解决方案就有:
1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。 1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。
2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。 2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。
3. If/Else的动态逻辑判断。伪代码简单示例如下: 3. If/Else的动态逻辑判断。伪代码简单示例如下:
``` ```
if (该设备有系统能力1) { if (该设备有系统能力1) {
运行系统能力1相关的代码; 运行系统能力1相关的代码;
} else { } else {
提示用户该设备不支持; 提示用户该设备不支持;
} }
``` ```
OpenHarmony支持的设备类型分为两大类: OpenHarmony支持的设备类型分为两大类:
1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示: 1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示:
![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png) ![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png)
或者module.json文件中的deviceTypes,如下图所示: 或者module.json文件中的deviceTypes,如下图所示:
![zh-cn_image_0000001266934142](figures/zh-cn_image_0000001266934142.png) ![zh-cn_image_0000001266934142](figures/zh-cn_image_0000001266934142.png)
简单来说,应用开发者基于典型设备类型的应用开发,仅需选择设备类型,系统完成分发或者安装的匹配逻辑。 简单来说,应用开发者基于典型设备类型的应用开发,仅需选择设备类型,系统完成分发或者安装的匹配逻辑。
2. 厂家自定义设备类型。由于厂家提供的系统能力千差万别,OpenHarmony允许厂家自己自定义设备的系统能力,但需要通过标准的格式形成一个ID,称为PCID(产品兼容性标识,Product Compatibility ID),并对外发布这个PCID,一般通过设备认证中心发布。应用开发者如果希望应用可以分发和安装到厂家自定义的设备上,就必须拿到对应的自定义设备PCID,否则就无法声明应用使用或调用的系统能力集(也是通过一个ID表示,称为RPCID,英文全名:Required Product Compatibility ID,中文名:要求的产品兼容性标识)。 2. 厂家自定义设备类型。由于厂家提供的系统能力千差万别,OpenHarmony允许厂家自己自定义设备的系统能力,但需要通过标准的格式形成一个ID,称为PCID(产品兼容性标识,Product Compatibility ID),并对外发布这个PCID,一般通过设备认证中心发布。应用开发者如果希望应用可以分发和安装到厂家自定义的设备上,就必须拿到对应的自定义设备PCID,否则就无法声明应用使用或调用的系统能力集(也是通过一个ID表示,称为RPCID,英文全名:Required Product Compatibility ID,中文名:要求的产品兼容性标识)。
鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。 鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。
## 编码时的API联想 ## 编码时的API联想
IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下: IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下:
![zh-cn_image_0000001267334018](figures/zh-cn_image_0000001267334018.gif) ![Video_20220408101413](figures/Video_20220408101413.gif)
## 动态逻辑判断 ## 动态逻辑判断
开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。 开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。
``` ```
import geolocation from'@ohos.geolocation'; import geolocation from'@ohos.geolocation';
const isLocationAvailable =canIUse('SystemCapability.Location.Location');
if (isLocationAvailable) { @Entry
console.log('该设备支持位置信息'); @Component
geolocation.getCurrentLocation((location) => { struct Index {
console.log(location.latitude, location.longitude); @State message: string = 'unknown';
}) aboutToAppear() {
} else { if (canIUse('SystemCapability.Location.Location')) {
console.log('该设备不支持位置信息'); geolocation.getCurrentLocation().then((location) => {
} this.message = 'current location: ' + JSON.stringify(location)
``` })
} else {
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** this.message = 'This device does not have the ability to get location.'
> 开发者通过 import 方式导入的模块,若当前设备不支持该模块,import 的结果为 undefined。故开发者在使用 API 时,需要判断其是否存在。 }
}
build() {
Row() {
Text(this.message).fontSize(24)
}
.justifyContent(FlexAlign.Center)
.width('100%')
.height('100%')
}
}
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 开发者通过 import 方式导入的模块,若当前设备不支持该模块,import 的结果为 undefined。故开发者在使用 API 时,需要判断其是否存在。
# 常见问题
## 如何查询设备类型
设备类型分为default(默认设备)、tablet、tv、wearable等,有多种查询设备类型的方式。
1. 通过命令行的方式查询设备类型。
通过命令行查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统参数介绍](https://gitee.com/openharmony/docs/blob/master/zh-cn/device-dev/subsystems/subsys-boot-init-sysparam.md)
```shell
# 方法一
hdc shell param get "const.build.characteristics"
# 方法二
hdc shell cat /etc/param/ohos.para | grep const.build.characteristic
```
2. 在应用开发过程中查询设备类型。
- 通过js接口查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-system-parameter.md)
```typescript
import parameter from '@ohos.systemparameter'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType: string = 'unknown'
aboutToAppear() {
try {
this.deviceType = parameter.getSync("const.build.characteristics")
} catch(e) {
console.log("getSync unexpected error: " + e)
}
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
- 通过deviceInfo查询设备类型,deviceInfo中各个字段的含义请参考[设备信息](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-device-info.md)
```typescript
import deviceInfo from'@ohos.deviceInfo'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown'
aboutToAppear() {
this.deviceType= deviceInfo.deviceType
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
## 如何在不同设备上为Ability配置不同的启动模式
应用由一个或多个Ability组成,Ability支持单实例、多实例和指定实例3种[启动模式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ability/stage-ability.md#%E5%90%AF%E5%8A%A8%E6%A8%A1%E5%BC%8F),启动模式可以在[配置文件(module.json5)](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)中通过launchType字段配置。启动模式对应Ability被启动时的行为,对启动模式的详细说明如下:
| 启动模式 | 描述 | 说明 |
| -------- | -------- | -------- |
| standard | 多实例 | 每次startAbility都会启动一个新的实例。 |
| singleton | 单实例 | 系统中最多只可以存在一个实例,startAbility时,如果系统中已存在相应的Ability实例,则复用该实例。 |
| specified | 指定实例 | 运行时由Ability内部业务决定是否创建多实例。 |
默认设备屏幕尺寸较小,采用standard启动模式不仅无法给用户提供便利,反而可能消耗更多系统资源,故通常采用singleton启动模式。平板屏幕尺寸较大且可能支持自由窗口,对于文档编辑、网页浏览等场景,使用standard启动模式可以提升用户体验。
本文中将默认设备和平板等归为同一泛类,推荐同一泛类的设备共用HAP包,同时本文也介绍了如何通过自适应布局能力和响应式布局能力开发出适配不同设备的页面。这里将补充介绍,如何实现Ability在不同设备上以不同的模式启动。
launchType字段配置为specified时,系统会根据AbilityStage的onAcceptWant的返回值确定是否创建新的实例。对于同一个应用,如果key已经存在,则复用该key对应的Ability,如果key不存在则新创建Ability。
可以将配置文件中的launchType字段配置为specified,同时在应用中加入如下代码以实现目标效果。
- 非平板设备,直接将设备类型作为key,保证每次启动的key相同,即以单实例模式运行。
- 平板设备,将设备类型与毫秒级时间戳叠加作为key,保证每次启动的key不同,即以多实例模式运行。
```typescript
// MyAbilityStage.ts
import AbilityStage from "@ohos.application.AbilityStage"
import deviceInfo from'@ohos.deviceInfo'
export default class MyAbilityStage extends AbilityStage {
...
private generateKey(): string {
// 如果是平板,则将设备类型和毫秒级时间戳叠加作为key,保证每次启动的key都不同
if (deviceInfo.deviceType === 'tablet') {
return deviceInfo.deviceType + (new Date()).valueOf()
}
// 如果不是平板,直接以设备类型作为key,每次启动的key相同
return deviceInfo.deviceType
}
onAcceptWant(want) {
return this.generateKey()
}
}
```
## 如何开启自由窗口
开发板上的自由窗口功能默认是关闭的,可以通过如下方式开启自由窗口功能。
```shell
# 取出开发板中的窗口配置文件,并将文件中的<decor enable="false"></decor>修改为<decor enable="true"></decor>
hdc file recv system/etc/window/resources/window_manager_config.xml ./
# 以可读写的模式重新挂载根目录,并更新开发板中的配置文件
hdc shell mount -o rw,remount /
hdc file send window_manager_config.xml system/etc/window/resources/window_manager_config.xml
# 重启开发板,配置生效
hdc shell reboot
```
开发板屏幕较小,通过手指操作窗口较为不便,建议外接鼠标进行操作。
- 鼠标在应用顶部悬停,即可召唤出窗口工具栏。
- 点击窗口工具栏中的缩放按钮(从左到右第二个),即可让应用以自由窗口的模式显示。
- 在自由窗口模式下,可以通过拖动应用窗口的边框或顶角,改变窗口尺寸同时触发应用显示刷新。
在调整窗口尺寸的过程中,窗口尺寸可能超出屏幕尺寸。此时应用显示正常,但受限于屏幕尺寸,在屏幕中只能看到应用部分区域的显示。可以通过移动窗口位置,查看应用其它区域的显示。
| 窗口操作按钮 | 悬浮窗口显示 | 调整窗口尺寸及位置查看不同的效果 |
| -------- | -------- | -------- |
| ![img2](figures/img2.png) | ![img3](figures/img3.png) | ![img4](figures/img4.png) |
## 如何限制自由窗口的尺寸调节范围
自适应布局可以保证窗口尺寸在一定范围内变化时,页面的显示是正常的。当窗口尺寸变化较大时,就需要额外借助响应式布局能力(如断点等)调整页面结构以保证显示正常。通常每个断点都需要开发者精心适配以获得最佳的显示效果,考虑到设计及开发成本等实际因素的限制,应用不可能适配从零到正无穷的所有窗口宽度。
不同设备或不同设备状态,系统默认的自由窗口尺寸的调节范围可能不同。开发者可以在[应用配置文件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)中限制应用中各个Ability的自由窗口尺寸调节范围,配置文件中影响自由窗口尺寸调节范围的字段如下表所示。
| 配置文件字段 | 数据类型 | 描述 |
| -------- | -------- | -------- |
| minWindowWidth | 数值 | 标识该ability支持的最小的窗口宽度,&nbsp;宽度单位为vp。 |
| minWindowHeight | 数值 | 标识该ability支持的最小的窗口高度,&nbsp;高度单位为vp。 |
| maxWindowWidth | 数值 | 标识该ability支持的最大的窗口宽度,宽度单位为vp。 |
| maxWindowHeight | 数值 | 标识该ability支持的最大的窗口高度,&nbsp;高度单位为vp。 |
| minWindowRatio | 数值 | 标识该ability支持的最小的宽高比。 |
| maxWindowRatio | 数值 | 标识该ability支持的最大的宽高比。 |
如下所示,通过配置文件分别限制自由窗口的最大和最小尺寸。
```
{
"module": {
...
"abilities": [
{
...
"minWindowWidth": 320,
"minWindowHeight": 240,
"maxWindowWidth": 1440,
"maxWindowHeight": 900,
"minWindowRatio": 0.5,
"maxWindowRatio": 2,
}
]
}
}
```
# 常见问题
## 如何查询设备类型
设备类型分为default(默认设备)、tablet、tv、wearable等,有多种查询设备类型的方式。
1. 通过命令行的方式查询设备类型。
通过命令行查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统参数介绍](../../../device-dev/subsystems/subsys-boot-init-sysparam.md)
```bash
# 方法一
hdc shell param get "const.build.characteristics"
# 方法二
hdc shell cat /etc/param/ohos.para | grep const.build.characteristic
```
2. 在应用开发过程中查询设备类型。
- 通过js接口查询指定系统参数(const.build.characteristics)进而确定设备类型,详见[系统属性](../../reference/apis/js-apis-system-parameter.md)
```ts
import parameter from '@ohos.systemParameter'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType: string = 'unknown';
aboutToAppear() {
try {
this.deviceType = parameter.getSync("const.build.characteristics");
} catch(e) {
console.log("getSync unexpected error: " + e);
}
}
build() {
Column() {
Text(this.deviceType).fontSize(24)
}
.width('100%')
.height('100%')
}
}
```
- 通过deviceInfo查询设备类型,deviceInfo中各个字段的含义请参考[设备信息](../../reference/apis/js-apis-device-info.md)
```ts
import deviceInfo from'@ohos.deviceInfo'
@Entry
@Component
struct GetDeviceTypeSample {
@State deviceType:string='unknown';
aboutToAppear() {
this.deviceType= deviceInfo.deviceType;
}
build() {
Column() {
Text(this.deviceType).fontSize()
}
.width('100%')
.height('100%')
}
}
```
## 如何查询屏幕/窗口尺寸
在应用开发过程中,为了在不同的设备上取得更好的显示效果,开发者可能需要查询屏幕尺寸或应用显示窗口尺寸。
- 通过display查询显示设备的属性(包括屏幕宽、高和屏幕密度等),详见[屏幕属性](../../reference/apis/js-apis-display.md)
```ts
private aboutToAppear() {
display.getDefaultDisplay()
.then((displayInfo) => {
console.info('Display width: '+ displayInfo.width);
console.info('Display height: '+ displayInfo.height);
console.info('Display density: '+ displayInfo.densityDPI);
})
.catch((error) => {
console.error('Failed to obtain the default display size. Cause: '+JSON.stringify(error));
})
}
```
- 通过window.getTopWindow获取应用窗口,进而查询应用窗口的宽高等,详见[窗口](../../reference/apis/js-apis-window.md)
注意必须在应用创建窗口后才可以拿到窗口对象,window.getTopWindow依赖AbilityContext作为入参,可以在MainAbility中通过this.context拿到AbilityContext对象,详见[Ability开发指导](../../ability/stage-ability.md)。可以在MainAbility的onCreate生命周期中拿到窗口尺寸,如下所示。
```ts
onCreate(want, launchParam) {
window.getTopWindow(this.context)
.then((windowClass) => { return windowClass.getProperties(); })
.then((topWindow) => {
console.info('Window width: '+ topWindow.windowRect.width);
console.info('Window height: '+ topWindow.windowRect.height);
})
.catch((error)=>{
console.error('Failed to obtain the window size. Cause: '+JSON.stringify(error));
})
}
```
> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:**
> 通过窗口尺寸调整显示更加“可靠”,因为顶部状态栏、三键导航等可能占据部分屏幕空间,另外部分设备上的应用可能以窗口形式显示。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册