diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\345\244\251\346\260\224\345\272\224\347\224\250UX\350\256\276\350\256\241\344\272\244\344\273\230\344\273\266_V1.0.zip" "b/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\345\244\251\346\260\224\345\272\224\347\224\250UX\350\256\276\350\256\241\344\272\244\344\273\230\344\273\266_V1.0.zip" new file mode 100644 index 0000000000000000000000000000000000000000..865d30b89e6646c00f44479346cc74362ac3c33e --- /dev/null +++ "b/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\345\244\251\346\260\224\345\272\224\347\224\250UX\350\256\276\350\256\241\344\272\244\344\273\230\344\273\266_V1.0.zip" @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:15bcc1b49648e188dcfa20cfd278b7a81148521095d26cd32899e31114a653c6 +size 15173412 diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\347\263\273\347\273\237\350\265\204\346\272\220\345\210\206\345\261\202\350\256\276\350\256\241\350\241\250_V1.0.xlsm" "b/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\347\263\273\347\273\237\350\265\204\346\272\220\345\210\206\345\261\202\350\256\276\350\256\241\350\241\250_V1.0.xlsm" index 0ae5cc3c60d095a79e0e52bbc9bcf245fb979014..25fc04076e244126d93a66a624e51f3ccd190ca5 100644 Binary files "a/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\347\263\273\347\273\237\350\265\204\346\272\220\345\210\206\345\261\202\350\256\276\350\256\241\350\241\250_V1.0.xlsm" and "b/zh-cn/application-dev/key-features/multi-device-app-dev/OpenHarmony_\347\263\273\347\273\237\350\265\204\346\272\220\345\210\206\345\261\202\350\256\276\350\256\241\350\241\250_V1.0.xlsm" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/Readme-CN.md b/zh-cn/application-dev/key-features/multi-device-app-dev/Readme-CN.md index 0d0083e21c6006f798dac41bcd9d5879b4fa2cc7..dd37facc4b2e9f554198ecbbc2d3f8d4c6e235a0 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/Readme-CN.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/Readme-CN.md @@ -1,61 +1,47 @@ -# 一次开发,多端部署 - -- [前言](about-this-document.md) -- [简介](introduction.md) -- 应用UX设计 - - [设计原则和要点](design-principles.md) - - 应用架构设计 - - [应用导航结构设计要求](navigation-design.md) - - [应用页面结构设计](page-design.md) - - 界面布局 - - [概述](layout-design-intro.md) - - 布局基础 - - [栅格系统](layout-grid.md) - - [自适应布局](layout-adaptive.md) - - [响应式布局](layout-responsive.md) - - [布局基础运用案例](layout-design-cases.md) - - 人机交互 - - [交互基础](interaction-basics.md) - - [常见输入方式](common-input-modes.md) - - [交互事件归一](design-interaction-events-unification.md) - - 视觉风格 - - [视觉基础](visual-style-basics.md) - - [色彩](visual-style-color.md) - - [字体](visual-style-font.md) - - [图标](visual-style-icon.md) - - [多态控件](design-polymorphic-components.md) - - [设计自检表](design-checklist.md) - - [资源](resource.md) -- [IDE使用](ide-usage.md) -- 一多能力的页面开发介绍 - - 布局能力 - - [布局能力简介](layout-intro.md) - - 自适应布局 - - [自适应布局简介](adaptive-layout-intro.md) - - [拉伸能力](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) - - 响应式布局 - - [栅格断点系统](grid-breakpoint.md) - - [媒体查询](media-query.md) - - [典型场景](responsive-layout-cases.md) - - [交互归一](interaction-events-unification.md) - - [多态组件](polymorphic-components.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) +# 一次开发,多端部署 + +- [前言](foreword.md) +- [简介](introduction.md) +- [从一个例子开始](start-with-a-example.md) +- 应用UX设计 + - [设计原则和要点](design-principles.md) + - 应用架构设计 + - [应用导航结构设计要求](navigation-design.md) + - [应用页面结构设计](page-design.md) + - 界面布局 + - [概述](interface-layout-design-intro.md) + - 布局基础 + - [栅格系统](design-grid.md) + - [自适应布局](design-adaptive-layout.md) + - [响应式布局](design-responsive-layout.md) + - [布局基础运用案例](design-layout-cases.md) + - 人机交互 + - [交互基础](interaction-basics.md) + - [常见输入方式](common-input-modes.md) + - [交互事件归一](design-interaction-event-normalization.md) + - 视觉风格 + - [视觉基础](visual-basics.md) + - [色彩](visual-style-color.md) + - [字体](visual-style-font.md) + - [图标](visual-style-icon.md) + - [多态控件](design-polymorphic-controls.md) + - [设计自检表](design-checklist.md) + - [设计交付](design-delivery.md) + - [资源](design-resources.md) +- [工程管理](ide-using.md) +- 页面开发的一多能力介绍 + - [简介](page-development-intro.md) + - 布局能力 + - [布局简介](layout-intro.md) + - [自适应布局](adaptive-layout.md) + - [响应式布局](responsive-layout.md) + - [典型布局场景](typical-layout-scenario.md) + - 典型页面场景 + - [应用市场首页](appgallery-home-page.md) + - [音乐专辑页](music-album-page.md) + - [交互归一](interaction-event-normalization.md) + - [多态组件](polymorphic-controls.md) + - [资源使用](resource-usage.md) +- [功能开发的一多能力介绍](development-intro.md) +- [案例应用](case.md) +- [常见问题](faq.md) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/about-this-document.md b/zh-cn/application-dev/key-features/multi-device-app-dev/about-this-document.md deleted file mode 100644 index d7d5aa2c556f370a306ce4c46dd321ecc32799ac..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/about-this-document.md +++ /dev/null @@ -1,40 +0,0 @@ -# 前言 - - -本指导的目的是快速及全面地指导读者使用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),方便读者查阅。 - -本指导在介绍过程中还包括一些“说明”。这些“说明”,表示例外情况或者额外信息的补充。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-equalization.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-equalization.md deleted file mode 100644 index 8db91ffcd054a26e8f91fa899c4f527941d7c7d1..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-equalization.md +++ /dev/null @@ -1,88 +0,0 @@ -# 均分能力 - - -均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。 - - -均分能力通常通过使用 **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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-extension.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-extension.md deleted file mode 100644 index 9d28ed7049b58ae611d8add81efb528d9a24806d..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-extension.md +++ /dev/null @@ -1,146 +0,0 @@ -# 延伸能力 - - -延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。 - - -延伸能力通常有两种实现方式: - - -- 通过[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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-hiding.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-hiding.md deleted file mode 100644 index 67464ca20984fb20b858b8559c6875266c6d15ee..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-hiding.md +++ /dev/null @@ -1,90 +0,0 @@ -# 隐藏能力 - - -隐藏能力是指容器组件内的子组件,按照其预设的显示优先级,随容器组件尺寸变化显示或隐藏,其中相同显示优先级的子组件同时显示或隐藏。它是一种比较高级的布局方式,常用于分辨率变化较大,且不同分辨率下显示内容有所差异的场景。主要思想是通过增加或减少显示内容,来保持最佳的显示效果。 - - -隐藏能力通过设置**布局优先级**(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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-intro.md deleted file mode 100644 index 7ed013110f346ad170849229925aa1ff182d5cc6..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-intro.md +++ /dev/null @@ -1,18 +0,0 @@ -# 自适应布局简介 - - -多设备间最大的差异是屏幕分辨率,差异分辨率适配离不开自适应布局的能力。针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力。这些布局可以独立使用,也可多种布局叠加使用。 - - -| 自适应布局类别 | 自适应布局能力 | 使用场景 | -| -------- | -------- | -------- | -| 自适应拉伸 | [拉伸能力](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) | 容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,**自动换行**。 | - - -下面我们依次介绍这几种自适应布局能力。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-proportion.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-proportion.md deleted file mode 100644 index c8ce9922e77114eb45fe1d7c47badac9d2a732eb..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-proportion.md +++ /dev/null @@ -1,94 +0,0 @@ -# 占比能力 - - -占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。 - - -占比能力通常有两种实现方式: - - -- 将子组件的宽高设置为父组件宽高的百分比,详见[尺寸设置](../../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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-scaling.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-scaling.md deleted file mode 100644 index 429d172db5e6a495a25cc90340d8d6256b6ab9ae..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-scaling.md +++ /dev/null @@ -1,66 +0,0 @@ -# 缩放能力 - - -缩放能力是指子组件的宽高按照预设的比例,随容器组件发生变化,且变化过程中子组件的宽高比不变。 - - -缩放能力通过使用百分比布局配合**固定宽高比**(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") - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-stretching.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-stretching.md deleted file mode 100644 index 1e2bee728e744a4345d452b5829cfb748f171115..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-stretching.md +++ /dev/null @@ -1,128 +0,0 @@ -# 拉伸能力 - - -拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。 - - -拉伸能力通常通过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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-wrapping.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-wrapping.md deleted file mode 100644 index 6b16f9ac6fbf61e266d1556c63f9ac919a14c85c..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout-wrapping.md +++ /dev/null @@ -1,72 +0,0 @@ -# 折行能力 - - -折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。 - - -折行能力通过使用 **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') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout.md b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout.md new file mode 100644 index 0000000000000000000000000000000000000000..5727bbb4841addd09243d925165779d1f2f879b0 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/adaptive-layout.md @@ -0,0 +1,759 @@ +# 自适应布局 + + +针对常见的开发场景,方舟开发框架提炼了七种自适应布局能力,这些布局可以独立使用,也可多种布局叠加使用。 + + + | 自适应布局类别 | 自适应布局能力 | 使用场景 | 实现方式 | +| -------- | -------- | -------- | -------- | +| 自适应拉伸 | [拉伸能力](#拉伸能力) | 容器组件尺寸发生变化时,增加或减小的空间**全部分配**给容器组件内**指定区域**。 | [Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)的flexGrow和flexShrink属性 | +| | [均分能力](#均分能力) | 容器组件尺寸发生变化时,增加或减小的空间**均匀分配**给容器组件内**所有空白区域**。 | [Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)、[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)或[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly | +| 自适应缩放 | [占比能力](#占比能力) | 子组件的宽或高**按照预设的比例**,随容器组件发生变化。 | 基于通用属性的两种实现方式:
- 将子组件的宽高设置为父组件宽高的百分比
- layoutWeight属性 | +| | [缩放能力](#缩放能力) | 子组件的宽高**按照预设的比例**,随容器组件发生变化,且变化过程中子组件的**宽高比不变**。 | [布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md)的aspectRatio属性 | +| 自适应延伸 | [延伸能力](#延伸能力) | 容器组件内的子组件,按照其**在列表中的先后顺序**,随容器组件尺寸变化显示或隐藏。 | 基于容器组件的两种实现方式:
- 通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现
- 通过[Scroll组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-scroll.md)配合[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)或[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)实现 | +| | [隐藏能力](#隐藏能力) | 容器组件内的子组件,按照其**预设的显示优先级**,随容器组件尺寸变化显示或隐藏。**相同显示优先级的子组件同时显示或隐藏**。 | [布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md)的displayPriority属性 | +| 自适应折行 | [折行能力](#折行能力) | 容器组件尺寸发生变化时,如果布局方向尺寸不足以显示完整内容,**自动换行**。 | [Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的wrap属性设置为FlexWrap.Wrap | + + +下面我们依次介绍这几种自适应布局能力。 + + +## 拉伸能力 + + +拉伸能力是指容器组件尺寸发生变化时,增加或减小的空间全部分配给容器组件内指定区域。 + + +拉伸能力通常通过[Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)中的flexGrow和flexShrink属性实现,flexGrow和flexShink属性常与flexBasis属性搭配使用,故将这三个属性放在一起介绍。 + + + | 属性 | 类型 | 默认值 | 描述 | +| -------- | -------- | -------- | -------- | +| flexGrow | number | 0 | 仅当父容器宽度大于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例拉伸,分配父容器的多余空间。 | +| flexShrink | number | 1 | 仅当父容器宽度小于所有子组件宽度的总和时,该属性生效。配置了此属性的子组件,按照比例收缩,分配父容器的不足空间。 | +| flexBasis | 'auto' \| [Length](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-types.md#length) | 'auto' | 设置组件在Flex容器中主轴方向上基准尺寸。'auto'意味着使用组件原始的尺寸,不做修改。
flexBasis属性不是必须的,通过width或height也可以达到同样的效果。当flexBasis属性与width或height发生冲突时,以flexBasis属性为准。 | + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 开发者期望将父容器的剩余空间全部分配给某空白区域时,也可以通过[Blank组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-blank.md)实现。注意仅当父组件为Row\Column\Flex组件时,Blank组件才会生效。 +> +> - 类Web开发范式也是通过flex-grow和flex-shrink实现拉伸能力,同时也支持配置flex-basis,详见[通用样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-styles.md)。 +> +> - 类Web开发范式没有提供blank组件,但可以通过div组件模拟blank组件的行为,如“<div style='flex-grow: 1; flex-shrink: 0; flex-basis: 0'></div>”。 + +**示例1** + + +本示例中的页面由中间的内容区(包含一张图片)以及两侧的留白区组成,各区域的属性配置如下。 + +* 中间内容区的宽度设置为400vp,同时将flexGrow属性设置为1,flexShrink属性设置为0。 + +* 两侧留白区的宽度设置为150vp,同时将flexGrow属性设置为0,flexShrink属性设置为1。 + +由上可知,父容器的基准尺寸是700vp(150vp+400vp+150vp)。 + +可以通过拖动底部的滑动条改变父容器的尺寸,查看布局变化。 + +* 当父容器的尺寸大于700vp时,父容器中多余的空间全部分配给中间内容区。 + +* 当父容器的尺寸小于700vp时,左右两侧的留白区按照“1:1”的比例收缩(即平均分配父容器的不足空间)。 + + +![zh-cn_image_0000001335796258](figures/zh-cn_image_0000001335796258.gif) + + + +``` +@Entry +@Component +struct FlexibleCapabilitySample1 { + @State containerWidth: number = 402 + + // 底部滑块,可以通过拖拽滑块改变容器尺寸。 + @Builder slider() { + Slider({ value: this.containerWidth, min: 402, max: 1000, style: SliderStyle.OutSet }) + .blockColor(Color.White) + .width('60%') + .onChange((value: number) => { + this.containerWidth = 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.containerWidth) + } + + this.slider() + }.width('100%').height('100%').backgroundColor('#F1F3F5') + } +} +``` + +**示例2** + + +文字和开关的尺寸固定,仅有中间空白区域(Blank组件)随父容器尺寸变化而伸缩。 + + +![zh-cn_image_0000001335316714](figures/zh-cn_image_0000001335316714.gif) + + + +``` +@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') + } +} +``` + + +## 均分能力 + + +均分能力是指容器组件尺寸发生变化时,增加或减小的空间均匀分配给容器组件内所有空白区域。它常用于内容数量固定、均分显示的场景,比如工具栏、底部菜单栏等。 + + +均分能力可以通过将[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)、[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)或[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)的justifyContent属性设置为FlexAlign.SpaceEvenly实现,即子元素在父容器主轴方向等间距布局,相邻元素之间的间距、第一个元素与行首的间距、最后一个元素到行尾的间距都完全一样。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 均分能力还可以通过其它方式实现,如使用[Grid网格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)或在每个组件间添加Blank组件等。 +> +> - 类Web开发范式中,通过将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的justify-content属性设置为space-evenly来实现均分布局。 + + +**示例:** + + +父容器尺寸变化过程中,图标及文字的尺寸不变,图标间的间距及图标离左右边缘的距离同时均等改变。 + + +![zh-cn_image_0000001335477142](figures/zh-cn_image_0000001335477142.gif) + + + +``` +@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') + } +} +``` + + +## 占比能力 + + +占比能力是指子组件的宽高按照预设的比例,随父容器组件发生变化。 + + +占比能力通常有两种实现方式: + + +- 将子组件的宽高设置为父组件宽高的百分比,详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)及[长度类型](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-types.md#length)。 + +- 通过layoutWeight属性配置互为兄弟关系的组件在父容器主轴方向的布局权重,详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/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组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)的columnsTemplate属性设置网格容器中列的数量及其宽度比例,或通过配置子组件在栅格(本章后文将详细介绍栅格系统)中占据不同的列数来实现占比能力。本小节仅介绍最基础和常用的实现方式,局限性较大或比非常小众的实现方式,本文不做展开介绍。 +> +> - 类Web开发范式同样支持以百分比的形式设置组件的宽高,详见[通用样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-styles.md)中关于width和height的介绍以及[长度类型介绍](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-appendix-types.md#%E9%95%BF%E5%BA%A6%E7%B1%BB%E5%9E%8B)。 +> +> - 与声明式开发范式中的layoutWeight属性类似,类Web开发范式提供了[flex-weight样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E5%8D%A0%E6%AF%94%E8%83%BD%E5%8A%9B)用于配置互为兄弟关系的组件在父容器主轴方向的布局权重。 + + +**示例:** + + +简单的播放控制栏,其中“上一首”、“播放/暂停”、“下一首”的layoutWeight属性都设置为1,因此它们按照“1:1:1”的比例均分父容器主轴方向的空间。 + + +将三个按钮的.layoutWeight(1)分别替换为.width('33%')、.width('34%')、.width('33%'),也可以实现与当前同样的显示效果。 + + +![zh-cn_image_0000001385757965](figures/zh-cn_image_0000001385757965.gif) + + + +``` +@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属性)实现当容器尺寸发生变化时,内容自适应调整。 + + +可以访问[布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解aspectRatio属性的详细信息。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 类Web开发范式同样提供了[aspect-ratio样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E5%9B%BA%E5%AE%9A%E6%AF%94%E4%BE%8B),用于固定组件的宽高比。 + + +**示例:** + + +为方便查看效果,示例中特意给Column组件加了边框。可以看到Column组件随着其Flex父组件尺寸变化而缩放的过程中,始终保持预设的宽高比,其中的图片也始终正常显示。 + + +![zh-cn_image_0000001335640862](figures/zh-cn_image_0000001335640862.gif) + + + +``` +@Entry +@Component +struct ScaleCapabilitySample { + @State sliderWidth: number = 400 + @State sliderHeight: number = 400 + + // 底部滑块,可以通过拖拽滑块改变容器尺寸 + @Builder slider() { + Slider({ value: this.sliderWidth, min: 100, max: 400, style: SliderStyle.OutSet }) + .blockColor(Color.White) + .width('60%') + .height(50) + .onChange((value: number) => { + this.sliderWidth = value; + }) + .position({ x: '20%', y: '80%' }) + Slider({ value: this.sliderHeight, min: 100, max: 400, style: SliderStyle.OutSet }) + .blockColor(Color.White) + .width('60%') + .height(50) + .onChange((value: number) => { + this.sliderHeight = 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.sliderWidth) + .width(this.sliderHeight) + + this.slider() + }.width('100%') + .height('100%') + .backgroundColor("#F1F3F5") + } +} +``` + + +## 延伸能力 + + +延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。它可以根据显示区域的尺寸,显示不同数量的元素。 + + +延伸能力通常有两种实现方式: + + +- 通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现。 + +- 通过[Scroll组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-scroll.md)配合[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)或[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)实现。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - List、Row或Column组件中子节点的在页面显示时就已经全部完成了布局计算及渲染,只不过受限于父容器尺寸,用户只能看到一部分。随着父容器尺寸增大,用户可以看到的子节点数目也相应的增加。用户还可以通过手指滑动触发列表滑动,查看被隐藏的子节点。 +> +> - 类Web开发范式同样可以使用[list组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-list.md)实现延伸能力。 +> +> - 类Web开发范式没有提供scroll组件,但可以将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的overflow样式设置为scroll(即div组件主轴方向上子元素的尺寸超过div组件本身的尺寸时进行滚动显示)来模拟scroll组件的行为。 + + +**示例:** + + +当父容器的尺寸发生改变时,页面中显示的图标数量随之发生改变。 + + +分别通过List组件实现及通过Scroll组件配合Row组件实现。 + + +![zh-cn_image_0000001335641246](figures/zh-cn_image_0000001335641246.gif) + + +(1)通过List组件实现。 + + + +``` +@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组件实现。 + +``` +@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属性)来控制显隐,当布局主轴方向剩余尺寸不足以满足全部元素时,按照布局优先级大小,从小到大依次隐藏,直到容器能够完整显示剩余元素。具有相同布局优先级的元素将同时显示或者隐藏。 + +可以访问[布局约束](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-layout-constraints.md),了解displayPriority属性的详细信息。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 类Web开发范式同样支持[display-index样式](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-atomic-layout.md#%E9%9A%90%E8%97%8F%E8%83%BD%E5%8A%9B),用于设置布局优先级。 + +**示例:** + +父容器尺寸发生变化时,其子元素按照预设的优先级显示或隐藏。 + +![zh-cn_image_0000001335485154](figures/zh-cn_image_0000001335485154.gif) + + +``` +@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') + } +} +``` + + +## 折行能力 + +折行能力是指容器组件尺寸发生变化,当布局方向尺寸不足以显示完整内容时自动换行。它常用于横竖屏适配或默认设备向平板切换的场景。 + +折行能力通过使用 **Flex折行布局** (将wrap属性设置为FlexWrap.Wrap)实现,当横向布局尺寸不足以完整显示内容元素时,通过折行的方式,将元素显示在下方。 + +可以访问[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md),了解Flex组件的详细用法。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 类Web开发范式通过将[div组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-container-div.md)的flex-warp样式设置为wrap来使用折行能力。 + +**示例:** + +父容器中的图片尺寸固定,当父容器尺寸发生变化,其中的内容做自适应换行。 + +![zh-cn_image_0000001385645821](figures/zh-cn_image_0000001385645821.gif) + + +``` +@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') + } +} +``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/appgallery-home-page.md b/zh-cn/application-dev/key-features/multi-device-app-dev/appgallery-home-page.md new file mode 100644 index 0000000000000000000000000000000000000000..a3f89db2847b975494c78470a8798e57f858c1b2 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/appgallery-home-page.md @@ -0,0 +1,271 @@ +# 应用市场首页 + + +本小节将以应用市场首页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[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 newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/architecture-design.md b/zh-cn/application-dev/key-features/multi-device-app-dev/architecture-design.md new file mode 100644 index 0000000000000000000000000000000000000000..e77c31f6aeda0b815245530efec0ac5e6bdfe4e1 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/architecture-design.md @@ -0,0 +1,7 @@ +# 应用架构设计 + + + +- **[应用导航结构设计要求](navigation-design.md)** + +- **[应用页面结构设计](page-design.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/case.md b/zh-cn/application-dev/key-features/multi-device-app-dev/case.md new file mode 100644 index 0000000000000000000000000000000000000000..79797d1d01fca795af6ce7fb3e747f79851b27a8 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/case.md @@ -0,0 +1,572 @@ +# 案例应用 + + +本章从OpenHarmony预置的系统应用中,选择短信应用作为典型的案例,从页面开发和工程结构的角度,介绍"一多"的具体实践。OpenHarmony的产品形态在不断丰富中,当前主要有默认设备和平板两种产品形态,本章的具体实践也将围绕这两种产品形态展开。 + + +## 概览 + +[短信](https://gitee.com/openharmony/applications_mms/tree/master)是OpenHarmony中预置的系统应用,主要包含信息查看、发送短信、接收短信、短信送达报告、删除短信等功能。在不同类型设备上,短信应用的功能完全相同,故短信应用适合使用[部署模型A](introduction.md#部署模型)(即:不同类型的设备上安装运行相同的HAP包或HAP包组合)。 + +本案例中,在会话详情页面利用[方舟开发框架](introduction.md#方舟开发框架)提供的“一多”能力,用一套代码同时适配默认设备和平板。 + + +### 工程结构 + +短信应用的工程结构如下图所示,当前该应用的功能较少,所以直接使用了DevEco Studio创建出的默认工程结构。具体采用何种形式的工程结构,并不影响应用的开发。但是使用推荐的工程结构,目录结构更清晰,拓展性也更好。 + +短信应用UI相关的逻辑集中在views和pages两个目录,分别存放公共组件及页面。当前短信应用主要包含如下页面: + +- 信息列表页面:首页,展示信息列表。 + +- 通知信息列表页面:将通知类信息集中在一起展示,与信息列表页面类似。 + +- 会话详情页面:展示与某联系人的所有信息往来。 + +- 报告详情页面:信息发送报告的详情页面。 + +- 设置页面:消息设置页面,如是否展示送达报告等。 + + +``` +/Mms/ + ├── doc # 资料 + ├── entry + │ └── src + │ └── main + │ ├── resources # 资源配置文件存放目录 + │ ├── config.json # 全局配置文件 + │ └── ets # ets代码目录 + │ ├── ServiceAbility # 后台常驻服务 + │ └── default # 业务代码目录 + │ ├── data # 自定义数据类型 + │ ├── model # 对接数据库 + │ ├── pages # 所有页面 + │ │ ├── conversation # 会话详情页面 + │ │ ├── conversationlist # 信息列表页面 + │ │ ├── index # 初始页面 + │ │ ├── info_msg # 通知信息列表页面 + │ │ ├── query_report # 报告详情页面 + │ │ └── settings # 设置页面 + │ ├── service # 业务逻辑 + │ ├── utils # 工具类 + │ ├── views # 自定义组件 + │ └── app.ets # 应用生命周期 + ├── signs # 签名 + └── LICENSE +``` + +短信应用在开发阶段,采用了一层工程结构。由于功能较为简单,所以并没有规划共用的feature和common目录,仅采用了一层product目录。 + +- 业务形态层(product) + 该目录采用IDE工程默认创建的entry目录,开发者可根据需要在创建Module时自行更改该目录名。不同产品形态,编译出相同的短信HAP包。 + + + +## 会话详情页面 + + +### 页面结构 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![overview_phone](figures/overview_phone.png) | ![overview_tablet](figures/overview_tablet.png) | + +会话详情页面在默认设备和平板上的样式如上图所示,会话详情页面可以划分为三个部分: + + | 页面组成 | 介绍 | +| -------- | -------- | +| 顶部标题栏 | ![zh-cn_image_0000001335699774](figures/zh-cn_image_0000001335699774.jpg) | +| 信息列表 | ![zh-cn_image_0000001386060209](figures/zh-cn_image_0000001386060209.jpg) | +| 底部输入栏 | ![zh-cn_image_0000001386179873](figures/zh-cn_image_0000001386179873.jpg) | + +接下来我们详细介绍各部分的实现。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 为了方便理解,我们对会话详情页面做了一定的精简,本小节仅介绍会话详情页面最基础的实现。 + + +### 顶部标题栏 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![zh-cn_image_0000001335539986](figures/zh-cn_image_0000001335539986.jpg) | ![top_title_tablet](figures/top_title_tablet.png) | + +顶部标题栏是一个简单的行布局,包含返回图标、联系人头像、联系人姓名和号码、拨号图标、设置图标共5个元素。其中,联系人姓名和号码以列布局的形式放在一起。 + +在默认设备和平板上,顶部标题栏的组件结构是相同的,仅联系人姓名和号码与拨号图标的间距不同。回顾方舟开发框架一多能力介绍,这个场景可以借助Blank组件使用拉伸能力。 + + 我们先实现联系人姓名和号码,用Flex组件作为父容器,其包含两个Text子组件,分别用于存放联系人姓名和号码。Flex组件的属性设置如下: +- direction: FlexDirection.Column:子组件在Flex容器上以列的方式排布,即主轴是垂直方向。 + +- justifyContent: FlexAlign.Center:子组件在Flex容器主轴(垂直方向)上居中对齐。 + +- alignItems: ItemAlign.Start:子组件在Flex容器交叉轴(水平方向)上首部对齐。 + +可以查看[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)及[Text组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-text.md)了解这两个组件各个属性的含义及详细用法。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![contact_details_phone](figures/contact_details_phone.png) | ![contact_details_tablet](figures/contact_details_tablet.png) | + + +``` +@Component + struct TopArea { + build() { + Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, + alignItems: ItemAlign.Start}) { + Text('张三').fontSize(16).fontColor("#182431") + Text('+123 4567 8901').fontSize(14).fontColor("#66182431") + } + } + } +``` + +接下来我们通过width属性和height属性设置四个图标的宽高(详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)),并将它们与联系人姓名和电话以及Blank组件一起放到Flex父容器中。为了便于查看效果,对顶部标题栏设置了淡蓝色的背景色。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![top_title_blank_phone](figures/top_title_blank_phone.png) | ![top_title_blank_tablet](figures/top_title_blank_tablet.png) | + + +``` +@Component + struct TopArea { + build() { + Flex({ alignItems: ItemAlign.Center }) { + Image($r('app.media.back')) + .width(24) + .height(24) + Image($r('app.media.contact')) + .width(40) + .height(40) + Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, + alignItems: ItemAlign.Start}) { + Text('张三').fontSize(16).fontColor("#182431") + Text('+123 4567 8901').fontSize(14).fontColor("#66182431") + } + Blank() // 拉伸能力 + Image($r("app.media.call")) + .width(24) + .height(24) + Image($r('app.media.dots')) + .width(24) + .height(24) + } + .width('100%') + .height(56) + .backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试 + } + } +``` + +当前标题栏中子组件的布局同预期还有些差异,接下来通过margin属性,设置各个元素的左右间距(详见[尺寸设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md))。如下图所示,最终顶部工具栏在默认设备和平板上都可以达到预期显示效果。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![top_title_done_phone](figures/top_title_done_phone.png) | ![top_title_done_tablet](figures/top_title_done_tablet.png) | + + +``` +@Component + struct TopArea { + build() { + Flex({ alignItems: ItemAlign.Center }) { + Image($r('app.media.back')) + .width(24) + .height(24) + .margin({ left:24 }) // 设置间距 + Image($r('app.media.contact')) + .width(40) + .height(40) + .margin({ left:16, right:16 }) // 设置间距 + Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, + alignItems: ItemAlign.Start}) { + Text('张三').fontSize(16).fontColor("#182431") + Text('+123 4567 8901').fontSize(14).fontColor("#66182431") + } + Blank() + Image($r("app.media.call")) + .width(24) + .height(24) + Image($r('app.media.dots')) + .width(24) + .height(24) + .margin({ left:16, right:24 }) // 设置间距 + } + .width('100%') + .height(56) + .backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试 + } + } +``` + + +### 底部输入栏 + +有了顶部工具栏的开发经验,可以发现底部输入栏的结构更为简单,它同样以Flex组件作为父容器,同时包含文本输入框(请访问[文本输入组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-textarea.md)查看详细介绍)和消息发送图标两个子节点。 + +![zh-cn_image_0000001335380378](figures/zh-cn_image_0000001335380378.jpg) + +为了便于查看的效果,我们同样给底部输入栏设置了淡蓝色到背景色。注意这里有一个特殊的地方,我们给TextArea设置了flexGrow(1)属性。flexGrow属性仅在父组件是Flex组件时生效,表示Flex容器的剩余空间分配给此属性所在的组件的比例,flexGrow(1)表示父容器的剩余空间全部分配给此组件,详见[Flex布局](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-flex-layout.md)。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![bottom_input_phone](figures/bottom_input_phone.png) | ![bottom_input_tablet](figures/bottom_input_tablet.png) | + + +``` +@Component + struct BottomArea { + build() { + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + TextArea({ placeholder:'短信' }) + .placeholderColor("#99000000") + .caretColor("#007DFF") + .backgroundColor("#F1F3F5") + .borderRadius(20) + .height(40) + .flexGrow(1) // 将父容器的剩余空间全部分配给此组件 + + Image($r("app.media.send")) + .height(36) + .width(36) + .opacity(0.4) + .margin({ left:12 }) + } + .height(72) + .width('100%') + .padding({ left:24, right:24, bottom:8, top:8 }) + .backgroundColor('#87CEFA') // 底部输入栏背景色,仅用于开发测试 + } + } +``` + + +### 信息列表 + +观察信息列表区域,可以发现它是由一个个消息气泡组成的,另外消息气泡在默认设备和平板上的布局有差异。本小节将围绕如下两个主题介绍如何实现消息列表。 + +- 如何实现自定义消息气泡组件。 + +- 如何在默认设备和平板上自适应布局。 + + | 默认设备 | 平板 | + | -------- | -------- | + | ![zh-cn_image_0000001386180233](figures/zh-cn_image_0000001386180233.jpg) | ![message_list_tablet](figures/message_list_tablet.png) | + +**消息气泡** + +先做一个最简单的消息气泡,通过borderRadius属性可以设置边框的圆角半径(详见[边框设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-border.md))。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![message_bubble_basic_phone](figures/message_bubble_basic_phone.png) | ![message_bubble_basic_tablet](figures/message_bubble_basic_tablet.png) | + + +``` +@Component +struct MessageBubble { + private content: string = "OpenHarmony" + + build() { + Column() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { + Text(this.content) + .fontSize(16) + .lineHeight(21) + .padding({ left: 12, right: 12, top: 8, bottom: 8 }) + .backgroundColor("#C0EBDF") + .borderRadius(24) + .fontColor("#182431") + }.width('100%') + } + .margin({left: 24, right: 24 }) + .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 + } +} +``` + +注意这个简单的消息气泡,左上角(或右上角)的样式,与实际期望不符。我们先修改发送消息右上角的样式,接收消息左上角的实现与之类似。 + +[Stack组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-stack.md)是一个堆叠容器,其子组件按照轴方向依次堆叠,后一个子组件覆盖前一个子组件。通过其alignContent接口,可以设置子组件在容器内的对齐方式,如alignContent: Alignment.TopStart代表子组件从左上角对齐。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![message_bubble_radius_phone](figures/message_bubble_radius_phone.png) | ![message_bubble_radius_tablet](figures/message_bubble_radius_tablet.png) | + + +``` +@Component +struct MessageBubble { + private content: string = "OpenHarmony" + private time: string = "今天 上午 10:35" + + build() { + Column() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { + Stack({ alignContent: Alignment.TopEnd }) { // 在左上角堆叠一个小色块 + Column() + .backgroundColor("#C0EBDF") + .borderRadius(4) + .width(24) + .height(24) + Text(this.content) + .fontSize(16) + .lineHeight(21) + .padding({ left: 12, right: 12, top: 8, bottom: 8 }) + .backgroundColor("#C0EBDF") + .borderRadius(24) + .fontColor("#182431") + } + }.width('100%') + } + .margin({left: 24, right: 24 }) + .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 + } +} +``` + +接下来我们在消息气泡下方加上时间显示,如下图所示,一个消息气泡自定义组件就基本完成了。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![message_bubble_recv_phone](figures/message_bubble_recv_phone.png) | ![message_bubble_recv_tablet](figures/message_bubble_recv_tablet.png) | + + +``` +@Component +struct MessageBubble { + private content: string = "OpenHarmony" + private time: string = "上午 10:35" + + build() { + Column() { + Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { + Stack({ alignContent: Alignment.TopEnd }) { + Column() + .backgroundColor("#C0EBDF") + .borderRadius(4) + .width(24) + .height(24) + Text(this.content) + .fontSize(16) + .lineHeight(21) + .padding({ left: 12, right: 12, top: 8, bottom: 8 }) + .backgroundColor("#C0EBDF") + .borderRadius(24) + .fontColor("#182431") + } + }.width('100%') + + // 在消息气泡底部增加时间显示 + Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, + justifyContent: FlexAlign.End}) { + Text(this.time) + .textAlign(TextAlign.Start) + .fontSize(10) + .lineHeight(13) + .fontColor("#99182431") + }.width('100%').margin({ left: 12, right: 0 }) + } + .margin({left: 24, right: 24 }) + .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 + } +} +``` + +发送出的消息和接收到的消息的消息气泡结构基本一致,可以通过增加一个标志位,让两种消息共用MessageBubble这个自定义组件,代码如下所示。将这个标志位设置true,可以查看接收消息的效果。 + + | 默认设备 | 平板 | +| -------- | -------- | +| ![message_bubble_send_phone](figures/message_bubble_send_phone.png) | ![message_bubble_send_tablet](figures/message_bubble_send_tablet.png) | + + +``` +@Component + struct MessageBubble { + private isReceived:boolean = false // 通过标志位,判断是发送or接收场景,进而使用不同的样式 + private content:string = "OpenHarmony" + private time:string = "今天 10:00" + + build() { + Column() { + Flex({ justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End, + alignItems: ItemAlign.Center }) { + Stack({ alignContent:this.isReceived? Alignment.TopStart: Alignment.TopEnd }) { + Column() + .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") + .borderRadius(4) + .width(24) + .height(24) + Text(this.content) + .fontSize(16) + .lineHeight(21) + .padding({ left:12, right:12, top:8, bottom:8 }) + .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") + .borderRadius(24) + .fontColor("#182431") + } + }.width('100%') + + Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, + justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End }) { + Text(this.time) + .textAlign(TextAlign.Start) + .fontSize(10) + .lineHeight(13) + .fontColor("#99182431") + }.width('100%') + .margin({ left:this.isReceived?12:0, right:this.isReceived?0:12 }) + } + .margin({left:24, right:24 }) + .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 + } + } +``` + +**栅格布局** + +回顾方舟开发框架一多能力,消息气泡在默认设备和平板上布局不同,可以借助栅格布局来解决。为了方便测试,我们预定义一个全局数组。 + + +``` +const globalMessageList:any[] = [ + { + 'time':'上午 10:20', + 'content':'项目介绍', + 'isReceived':false + }, + { + 'time':'上午 10:28', + 'content':'OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。', + 'isReceived':false + },{ + 'time':'上午 10:32', + 'content':'技术架构', + 'isReceived':true + }, + { + 'time':'上午 10:35', + 'content':'OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的组件。', + 'isReceived':true + } + ] +``` + +结合[栅格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcontainer.md)的定义,考虑我们当前的实际场景,GridRow的各参数设置如下。 + +- columns:栅格组件中的列数,当前场景默认12列即可。 + +- gutter:栅格布局列间距,当前场景未使用该参数,默认设置为0即可。 + +- margin: 栅格布局两侧间距,在开发消息气泡组件时,已经设置了左右间距,故该属性也默认配置为0。 + +栅格中仅包含我们自定义的消息气泡组件,该组件在各断点上的参数配置如下。 + + | 断点 | 窗口宽度(vp) | 栅格总列数 | 消息气泡占用的列数 | 接收场景偏移的列数 | 发送场景偏移的列数 | +| -------- | -------- | -------- | -------- | -------- | -------- | +| sm | [320, 520) | 12 | 12 | 0 | 0 | +| md | [520, 840) | 12 | 8 | 0 | 4 | +| lg | [840, +∞) | 12 | 8 | 0 | 4 | + + | 默认设备 | 平板 | +| -------- | -------- | +| ![message_list_phone](figures/message_list_phone.png) | ![message_list_tablet](figures/message_list_tablet.png) | + + +``` +@Component +export default struct MessageItem { + private isReceived: boolean + private content: string + private time: string + + build() { + GridRow() { + GridCol({span: {sm: 12, md: 8, lg: 8}, + offset: {sm: 0, md: this.isReceived? 0 : 4, lg: this.isReceived? 0 : 4}}) { + Flex({ justifyContent: FlexAlign.End, alignItems: ItemAlign.End }) { + MessageBubble({ + isReceived: this.isReceived, + content: this.content, + time: this.time + }) + } + } + } + } +} + +@Entry +@Component +struct Conversation { + build() { + Column() { // 验证效果 + MessageItem({ + isReceived: globalMessageList[1].isReceived, + content: globalMessageList[1].content, + time: globalMessageList[1].time + }) + MessageItem({ + isReceived: globalMessageList[3].isReceived, + content: globalMessageList[3].content, + time: globalMessageList[3].time + }) + }.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 + } +} +``` + + +### 组合成型 + +现在会话详情页面的顶部标题栏、信息列表及底部输入栏都已经准备完毕,将这三部分组合起来即可得到完整的页面。 + +- 通过[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)将三个部分组合起来,注意justifyContent: FlexAlign.SpaceBetween配置项是将Flex组件中的元素按照主轴方向均匀分配,其中第一个元素与顶部对齐,最后一个元素与底部对齐。 + +- 通过[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)和[ForEach语法](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-rending-control-syntax-foreach.md),显示整个消息列表。 + + | 默认设备 | 平板 | + | -------- | -------- | + | ![overview_phone](figures/overview_phone.png) | ![overview_tablet](figures/overview_tablet.png) | + + +``` +@Entry + @Component + struct Conversation { + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, + justifyContent: FlexAlign.SpaceBetween }) { + Column() { + TopArea() // 顶部标题栏 + List() { // 消息列表 + ForEach(globalMessageList, (item, index) => { + ListItem() { + MessageItem({ + isReceived: item.isReceived, + content: item.content, + time: item.time + }) + }) + } + .listDirection(Axis.Vertical) + .edgeEffect(EdgeEffect.Spring) + } + BottomArea() // 底部输入栏 + } + .backgroundColor("#F1F3F5") + .width('100%') + .height('100%') + } + } +``` + + +## 总结 + +短信应用在默认设备和平板上的功能完全相同,因此选择了部署模型A。借助方舟开发框架一多能力,短信应用实现了在默认设备和平板上共用同一份代码,同时自然也共用安装包。 + +在实际开发过程中,会话详情页面需要从底层做数据交互,同时还要支持信息选择、信息删除、信息发送状态、输入框与输入法联动等等功能,会比本小节中介绍的基础版本复杂很多。读者如果对这部分感兴趣,可以访问[短信应用开源代码仓](https://gitee.com/openharmony/applications_mms/tree/master),了解会话详情页面的详细实现。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/cases-home-screen.md b/zh-cn/application-dev/key-features/multi-device-app-dev/cases-home-screen.md deleted file mode 100644 index c433e7df0e3f29f74428690141305c9131fd2765..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/cases-home-screen.md +++ /dev/null @@ -1,111 +0,0 @@ -# 桌面应用 - - -[桌面](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%左右**。在后续拓展其它设备类型时,依然可以使用此部分公共代码。这既可以提高多设备场景开发效率,同时也可以降低后期的维护成本。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/common-input-modes.md b/zh-cn/application-dev/key-features/multi-device-app-dev/common-input-modes.md index f86e56aef1a7e97439fd0aab4fdbec476b56dab2..11f707ede0a1b66df1724b7584859b282a8296ff 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/common-input-modes.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/common-input-modes.md @@ -5,7 +5,7 @@ **基于触控的交互** -很多设备都拥有支持多点触控的屏幕,允许用户使用手指和/或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。 +很多设备的屏幕都支持多点触控,允许用户通过手指或手写笔进行交互。它们与屏幕的接触状态、数量以及运动行为被识别成触控手势和操作,可以支持多种交互功能和体验(例如点击、滑动、缩放、旋转)。在多数情况下,应将触控交互作为用户首要的交互方式。 以下是基础的手势操作: diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-adaptive.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-adaptive-layout.md similarity index 83% rename from zh-cn/application-dev/key-features/multi-device-app-dev/layout-adaptive.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-adaptive-layout.md index 9f4fbac24fc2c8ab47eff91bcc546aae517c30e2..3e9538789ead02d02b62eed756e1e53e6dfd49d6 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-adaptive.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-adaptive-layout.md @@ -1,72 +1,72 @@ -# 自适应布局 - - -自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。 - - -## 自适应拉伸 - -某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。 - -左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。 - -![zh-cn_image_0000001258762686](figures/zh-cn_image_0000001258762686.gif) - -均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。 - -![zh-cn_image_0000001291556325](figures/zh-cn_image_0000001291556325.gif) - -自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。 - -当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。 - -![zh-cn_image_0000001245276368](figures/zh-cn_image_0000001245276368.png) - - -## 自适应缩放 - -组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。 - -完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。 - -![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif) - -占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。 - -![zh-cn_image_0000001245116688](figures/zh-cn_image_0000001245116688.gif) - -自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。 - -不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。 - -![zh-cn_image_0000001292842113](figures/zh-cn_image_0000001292842113.gif) - - -## 自适应延伸 - -组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。 - -同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。 - -![zh-cn_image_0000001291556369](figures/zh-cn_image_0000001291556369.gif) - -不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。 - -![zh-cn_image_0000001245276416](figures/zh-cn_image_0000001245276416.gif) - -自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。 - -注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。 - - -## 自适应折行 - -定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。 - -例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。 - -![zh-cn_image_0000001291675805](figures/zh-cn_image_0000001291675805.png) - -自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。 - -自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout-intro.md)”。 +# 自适应布局 + + +自适应布局是通过设定元素与外部容器的相对关系实现的。当外部容器大小、位置等发生变化时,元素即可以根据相对关系自动变化以适应外部环境的变化。通常自适应布局能根据vp/px变化进行无级连续的变化。 + + +## 自适应拉伸 + +某单个内容或某组内容的显示宽度不是固定值,而是通过相对参照物的方式来确定其显示宽度。当参照物的宽度发生变化时,内容或内容间距的宽度随之发生自适应拉伸。 + +左右拉伸:例如,列表开关组合中,在窗口宽度变化时,开关控件固定宽度并相对列表的右边缘位置固定,整个组合与文本宽度均自适应变化。 + +![拉伸能力](figures/拉伸能力.gif) + +均分拉伸:例如,在图标型网格中,当窗口宽度变化时,入口图标间距与图标离左右边缘间距同时均等变化。 + +![均分能力](figures/均分能力.gif) + +自适应拉伸适用于文字、普通按钮、间距等展示宽度灵活,对宽高比不敏感的内容和内容组合。 + +当可能出现的拉伸宽度不足以显示默认内容时,应根据场景选择优先保证内容完整或者优先保证其他内容的屏效,并进行截断或换行等组合适配。 + +![拉伸注意场景](figures/拉伸注意场景.png) + + +## 自适应缩放 + +组件的显示大小是固定比例,通过相对参照物的方式来确定其宽或高。当参照物的大小发生变化时,元素的大小随之发生自适应缩放。 + +完整缩放:例如,在宽度或高度变化时,时钟始终保证表盘完整展示并根据较短边决定宽高。 + +![zh-cn_image_0000001291675753](figures/zh-cn_image_0000001291675753.gif) + +占比缩放:例如,带主体和背景的插画,画面内容根据宽度变化裁切,根据高度变化按50%比例缩放。 + +![缩放案例](figures/缩放案例.gif) + +自适应缩放适用于图片、圆形按钮、banner、反应真实物体形状的图像等必须保证宽高比的内容。 + +不推荐将所有元素同时缩放、或某内容放大过大超过屏幕50%。这将导致获取信息量不增反减,不符合用户预期。 + +![4.3-2](figures/4.3-2.png) + + +## 自适应延伸 + +组件的显示数量不是固定的,而是通过相对参照物的方式来确定其显示数量。当参照物的宽度发生变化时,组件随之发生自适应延伸显示更多数量。 + +同功能内容延伸:例如,子页签和可滑动宫格在默认宽度下通过露出最后内容,提示右方有更多入口,在宽度变化时,可在每个元素宽度不变、保持滑动交互时显示更多数量。 + +![延长能力](figures/延长能力.gif) + +不同功能内容延伸或隐藏:例如,默认处于同一排的不同音乐播放按钮优先级不同,在宽度变化时可延伸或隐藏低优先级的按钮,最大化适应不同窗口尺寸。 + +![隐藏能力](figures/隐藏能力.gif) + +自适应延伸/隐藏适用于页签、操作块、推荐栏目等具有相同交互层级且有更多数据可以填充的内容。 + +注意:需要判断因隐藏而不展示的内容对功能完整性是否有影响,并考虑通过滑动或“更多”按钮提供查看使用该内容的方式。 + + +## 自适应折行 + +定义了折行能力的组件,可以根据组件容器的可用空间,体现纵向布局或者横向布局。 + +例如,在宽度足够时,操作块位于同一行,在宽度变小时,可根据内容能显示的宽度纵向排布。 + +![折行案例分镜](figures/折行案例分镜.png) + +自适应折行适用于页签、操作块、内容流等具有相同交互层级,且希望保证类型和数量完整性的内容。 + +自适应布局对应OpenHarmony系统提供的自适应布局能力中的拉伸、均分、缩放、占比、延伸、隐藏、折行。自适应布局能力详见本文“[自适应布局](adaptive-layout.md)”相关介绍。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-checklist.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-checklist.md index ec3e259f84e5af7ac583703dd5ab745468cb1903..740099c4481da1f2c553bb53f4b410c6e499e45b 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/design-checklist.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-checklist.md @@ -1,24 +1,27 @@ -# 设计自检表 - - -设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。 - - -自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。 - -请参考以下表格范围内提出的要求对应用进行检查。 - -| **类型** | **条目** | **说明** | -| -------- | ------------------ | ------------------------------------------------------------ | -| 应用架构 | 导航结构 | 保证同一应用/服务在各设备上导航结构一致。 | -| | 界面框架 | 尽量使用推荐的常用界面架构,以更好达到一多效果。 | -| 布局 | 自适应布局 | 关注布局标注是否逻辑合理,是否具备自适应能力。保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形地正常显示。 | -| | 响应式布局 | 关注布局是否更有效利用屏幕控件,是否具备响应式能力。保证在不同尺寸和分辨率的设备上不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)。 | -| | 页面结构 | 尽量使用推荐的常用页面结构,以更好达到一多效果。 | -| | 页面结构优化 | 在通用能力不适用业务诉求时,进行页面特殊优化,保证在具体设备上的使用体验。 | -| 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 | -| | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 | -| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 | -| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 | -| | 字体 | 尽量使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 | +# 设计自检表 + + +设计自检表详细列举出了在全场景设备设计和开发过程中应当注意的设计规则,这将帮助应用减少用户舆情且提升用户体验的一致性。 + + +自检表的要求范围分为“必选”与“推荐”两类。必选类一般为已总结出的较优解决方案或效果,表示相关设计需要按照此原则统一执行;推荐类指可能受应用品牌风格或业务特殊性影响,可适量做出修改。 + + +请参考以下表格范围内提出的要求对应用进行检查。 + +| **类型** | **条目** | **说明** | +| -------- | ------------------ | ------------------------------------------------------------ | +| 应用架构 | 导航结构 | 在各设备上页面导航结构保持一致(同时出多个设备的UX设计)。 | +| 布局 | 拉通设计 | 拉通各设备的布局设计,保证在不同尺寸和分辨率的设备上能够无错位/不截断/不变形/不过多空白(50%以上)/不过于拥挤(间距小于16vp,明显截断)/无大图大字体地正常显示。 | +| | 响应式设计 | 栅格布局只能占N列以及N列内部的Gutter,不包含N列两侧的Gutter。 | +| | 响应式设计 | 明确标注使用什么类型的栅格、给出在不同断点下栅格三要素取值。 | +| | 响应式设计 | 按容器去对齐栅格,而不是内部子元素对齐栅格。 | +| | 响应式设计 | 栅格除了页面布局设计外,在做局部栅格设计时,需要通过明显方式如颜色等进行标注区分,避免混淆。 | +| | 响应式设计 | 禁止出现标注了栅格但实际没有通过栅格进行布局设计,避免混淆。 | +| | 自适应设计 | 非栅格设计场景下,明确标注自适应布局能力。自适应布局能力有:拉伸、均分、占比、缩放、延伸、隐藏、折行。 | +| 人机交互 | 输入方式 | 需保证在各设备上完整支持触摸、鼠标、触控、键盘、遥控器、摇杆等交互方式,并符合标准定义。 | +| | 交互归一 | 应使用系统提供的控件以达到一致的交互体验。如有定制,需保证在各场景下,不同输入设备上的操作与指南要求一致。需特别注意鼠标行为。 | +| 视觉风格 | 单位 | 用于界面布局的单位应全部使用vp。只针对严格控制元素尺寸的场景使用px。 | +| | 色彩 | 用于色彩的赋值应使用分层参数。推荐支持深色模式,需保证界面在系统切换色彩模式时没有识别性问题。 | +| | 字体 | 使用fp为文字大小单位,需要响应系统大字体模式,确保系统调节字体大小后,界面字体能响应变化大小,并且界面布局没有出现布局错乱问题。 | | 多态控件 | 支持常用的控件状态 | 确保控件不同状态下的视觉效果没有缺失。控件的常用状态有:正常态、不可用态、点击态、获焦态、激活态、悬停态。 | \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-delivery.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-delivery.md new file mode 100644 index 0000000000000000000000000000000000000000..863233e230a40323ea6ad9fcb5b9f0650a6c4337 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-delivery.md @@ -0,0 +1,109 @@ +# 设计交付 + + +## 概述 + +为了将UX设计详尽准确地实现并传递给开发者,设计师需向开发者提供必要的设计交付件,包括但不限于:应用规格说明、交互流程、视觉效果、视觉标注、视觉规格说明、切图资源、动效参数资源、音效资源等内容。 + +面向多设备多尺寸的应用UX设计交付件,以完整说明界面布局与视觉设计为主要目的,至少应包含:效果图、标注图、规格说明和切图资源。 + +下面将分别介绍不同交付内容的用途与规范。 + +![4.8-交付4件套](figures/4.8-交付4件套.png) + + +## 效果图 + +效果图是表达UX设计的关键内容,用于直观呈现目标体验的静态效果,并作为开发者与测试工程师的实现与验收依据。效果图一般为jpg或png格式。 + +在优秀的设计交付件中,针对不同前置条件下,各交互流程所途经的每个界面都应匹配效果图。对于大量重复使用的组件元素,如弹窗和即时反馈,亦可配合规格统一说明,不做过多重复设计。 + +在多设备设计中,为了清晰表达设计效果,设计师仍需要针对不同尺寸的关键界面提供符合规范的效果图。关键界面包括且不限于: + +- 应用的首页 + +- 可以从首页直接进入的各二级界面 + +- 核心使用流程途经的各界面 + +- 能体现多数界面的自适应与响应式规格的典型界面 + +不同尺寸的效果图,至少应包含小设备、中设备、大设备。根据业务涉及的设备特点,可补充超小尺寸效果,及不同设备的横竖屏效果,提前充分验证并优化UX设计体现的差异性、一致性、灵活性、兼容性。 + +对应不同设备效果图的设计画板尺寸推荐如下: + + | 设备类型 | 屏幕宽度 | 画板尺寸(vp) | +| -------- | -------- | -------- | +| 超小设备 | [0, 320) | 240\*320 | +| 小设备 | [320, 520) | 360\*780 | +| 中设备 | [520, 840) | 677\*763 | +| 大设备 | [840, +) | 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) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-grid.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-grid.md similarity index 82% rename from zh-cn/application-dev/key-features/multi-device-app-dev/layout-grid.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-grid.md index 3b2e9e4db7bee663b46cd5155b47f3c27f411e7e..7f1173fafc4c356a142c37d3766f814237142789 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-grid.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-grid.md @@ -1,17 +1,20 @@ -# 栅格系统 - - -栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。 - - -通过栅格系统进行布局,可以更好达到多设备下布局的一致性。 - - -![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。 - - -![zh-cn_image_0000001305734113](figures/zh-cn_image_0000001305734113.png) - +# 栅格系统 + + +栅格系统是一个多设备下通用的辅助定位系统,适用于应用窗口的整体布局,也支持界面局部内容使用。栅格系统由 Margin,Gutter,Column 三个属性构成。Margin是相对屏幕、窗口等父容器左右边缘的距离,决定了内容可展示的整体宽度;Gutter是每个Column的间距,决定内容间的紧密程度; Column是内容的占位元素,其数量决定了内容的布局复杂度。Margin大小、Gutter大小、Column数量综合决定Column的具体宽度。 + + +通过栅格系统进行布局,可以更好达到多设备下布局的一致性。 + + +![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。 + + +![栅格系统例](figures/栅格系统例.png) + + +栅格系统对应OpenHarmony系统提供的布局能力中的栅格布局,详见本文 “[栅格布局](responsive-layout.md#栅格布局)”相关介绍。 + diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-events-unification.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-event-normalization.md similarity index 98% rename from zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-events-unification.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-event-normalization.md index bb44760cdfef77df112ae9652188d8dba9d72805..330cb03c08bed504432e3b99b4a64459ff6a46d9 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-events-unification.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-interaction-event-normalization.md @@ -1,54 +1,54 @@ -# 交互事件归一 - - -本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。** - - -![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png) - - -## 打开/切换对象 - -用户通过点击某个元素触发功能、访问新页面、或改变自身状态。 - - | **输入方式** | **交互行为** | **示意** | -| -------- | -------- | -------- | -| 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) | -| 鼠标 | 左键单击 / 左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) | -| 触摸板 | 单指单击 / 单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) | -| 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) | - -一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。 - -在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。 - - -## 显示菜单 - -某个元素上显示弹出菜单或快捷方式菜单。 - -![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg) - - | **输入方式** | **交互行为** | -| -------- | -------- | -| 触屏 | 单指长按 | -| 鼠标 | 右键单击(与PC一致)/ 左键长按(保留触屏习惯) | -| 触摸板 | 双指轻单击/重单击(与PC一致)/ 单指重长按(保留触屏习惯) | -| 键盘 | (无通用操作) | - -这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。 - -凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。 - - -## 拖拽对象 - -直接指向某个元素并移动到界面其他位置 - -![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png) - - | **输入方式** | **交互行为** | -| -------- | -------- | -| 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 | -| 鼠标 / 触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 | -| 键盘 | (无通用操作) | +# 交互事件归一 + + +本章节描述了在多种交互任务或场景下,应用在触屏上和其它常用的输入方式(例如鼠标、触摸板、键盘)上分别对应的正确的交互规则。**设计师和开发者应保证在当前输入方式下应用能够以正确的、符合用户习惯的交互规则进行响应。** + + +![zh-cn_image_0000001224333656](figures/zh-cn_image_0000001224333656.png) + + +## 打开/切换对象 + +用户通过点击某个元素触发功能、访问新页面、或改变自身状态。 + + | **输入方式** | **交互行为** | **示意** | +| -------- | -------- | -------- | +| 触屏 | 单指单击 | ![zh-cn_image_0000001280472681](figures/zh-cn_image_0000001280472681.png) | +| 鼠标 | 左键单击 / 左键双击 | ![zh-cn_image_0000001236472600](figures/zh-cn_image_0000001236472600.png) | +| 触摸板 | 单指单击 / 单指双击 | ![zh-cn_image_0000001280232265](figures/zh-cn_image_0000001280232265.png) | +| 键盘 | 移动焦点到对象上后按下Enter键 | ![zh-cn_image_0000001280472701](figures/zh-cn_image_0000001280472701.png) | + +一般地,触屏手指的按下/抬起行为对应于光标的按下/抬起行为。 + +在一些特殊场景,可能会存在使用鼠标/触摸板双击打开对象的交互方案,例如电脑模式下打开桌面应用或文件。此类情况需由应用单独特殊处理,且同一功能不能同时支持单击和双击两种交互方式。 + + +## 显示菜单 + +某个元素上显示弹出菜单或快捷方式菜单。 + +![zh-cn_image_0000001268533753](figures/zh-cn_image_0000001268533753.jpg) + + | **输入方式** | **交互行为** | +| -------- | -------- | +| 触屏 | 单指长按 | +| 鼠标 | 右键单击(与PC一致)/ 左键长按(保留触屏习惯) | +| 触摸板 | 双指轻单击/重单击(与PC一致)/ 单指重长按(保留触屏习惯) | +| 键盘 | (无通用操作) | + +这里的菜单指的是广义的菜单,即用于展示用户可执行的操作的临时性弹出窗口。 + +凡是在触屏上通过长按显示的菜单,都需要支持鼠标右键单击和触摸板双指单击的触发方式。 + + +## 拖拽对象 + +直接指向某个元素并移动到界面其他位置 + +![zh-cn_image_0000001268653953](figures/zh-cn_image_0000001268653953.png) + + | **输入方式** | **交互行为** | +| -------- | -------- | +| 触屏 | 长按某对象后触发可拖拽状态,然后移动手指改变对象位置。 | +| 鼠标 / 触摸板 | 鼠标左键或触摸板单指按下即可拖拽对象(无需长按等待)。 | +| 键盘 | (无通用操作) | diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-cases.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-layout-cases.md similarity index 80% rename from zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-cases.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-layout-cases.md index 68bd434b4ce3c2da83753453cba3f2a4d63e8329..3a0e6ac6caccbd319aa4bda045073c6535e5366f 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-cases.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-layout-cases.md @@ -1,66 +1,66 @@ -# 布局基础运用案例 - - -## 平级导航的复合网格视图 - -平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 - -例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。 - -![zh-cn_image_0000001317088945](figures/zh-cn_image_0000001317088945.png) - -- 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。 - -- 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。 - -- 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。 - -- 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。 - -在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。 - -![zh-cn_image_0000001317328797](figures/zh-cn_image_0000001317328797.png) - -当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。 - -![zh-cn_image_0000001268448854](figures/zh-cn_image_0000001268448854.png) - - -## 层级导航的列表视图 - -层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。 - -例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。 - -![zh-cn_image_0000001268128998](figures/zh-cn_image_0000001268128998.png) - -在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。 - - -## 专辑详情页面 - -专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。 - -例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。 - -- 标题栏:采用自适应拉伸。 - -- 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。 - -- 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。 - -- 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。 - -- 播放栏:固定在界面底部,保持左右拉伸即可。 - -![zh-cn_image_0000001268288870](figures/zh-cn_image_0000001268288870.png) - -在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。 - -歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。 - -![zh-cn_image_0000001268608782](figures/zh-cn_image_0000001268608782.png) - -当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。 - -![zh-cn_image_0000001317208833](figures/zh-cn_image_0000001317208833.png) +# 布局基础运用案例 + + +## 平级导航的复合网格视图 + +平级导航的复合网格视图常出现在同时展示多种不同内容的界面。 + +例如,市场类应用作为典型的平级导航,其首页不同板块采用了不同布局能力。 + +![一多-布局1](figures/一多-布局1.png) + +- 标题栏与搜索栏:因元素单一、位置固定在顶部,因此适合采用自适应拉伸,并在大尺寸界面中从纵排变为横排,充分利用顶部区域。 + +- 运营横幅:在小设备上默认为多张轮播展示,随宽度变化采用自适应缩放,在中尺寸界面通过重复布局变为并排多张。 + +- 图标型网格:对于数量固定、且子内容重要程度相同的网格,需保证完全展示,可采用均分拉伸。对于数量不限的网格,则采用自适应延伸,在更大宽度上展示更多数量。 + +- 底部导航栏:导航类控件本身综合了均分和折行,在宽度变化时能占用均等宽度并在足够宽度下并排,当在大尺寸界面中,挪移到左边,使不同页签距离更近、同时符合视觉走向。 + +在横竖屏切换时,也保持了一致的布局能力,实际上完成了大尺寸和中尺寸的切换。 + +![一多-布局2](figures/一多-布局2.png) + +当界面出现在智慧屏上,虽然同是大尺寸界面,为了符合设备样式和遥控器交互规则,搜索栏转化为图标入口,导航栏挪移到页面上部。 + +![一多-布局3](figures/一多-布局3.png) + + +## 层级导航的列表视图 + +层级导航的列表视图常出现在多类简单信息并列或多入口业务入口的界面。 + +例如,设置类应用作为典型的层级导航,其列表控件采用自适应拉伸。 + +![布局基础案例-层级导航-设置](figures/布局基础案例-层级导航-设置.png) + +在中尺寸设备中,为避免中间区域空白过大,采用缩进布局,大尺寸设备中,为充分利用横向空间,建议采用栅格系统形成分栏效果,并让列表元素在各自区域保持拉伸。 + + +## 专辑详情页面 + +专辑详情不限于展示音乐内容,也用于展示视频、短视频、电台、书本等内容类合集。 + +例如,歌单类界面作为典型的内容垂类页面,其总体分为标题栏、歌单信息、歌单操作、歌单列表、播放栏几个板块。 + +- 标题栏:采用自适应拉伸。 + +- 歌单信息:采用自适应缩放,并在中尺寸界面进行缩进处理使内容呈现协调。 + +- 歌单操作:板块内部采用均分拉伸,在小尺寸设备上利用纵向空间、中尺寸设备上挪移到歌单封面右边。 + +- 歌单列表:板块内部采用左右拉伸,在中尺寸设备上可与歌单信息使用相同缩进布局。 + +- 播放栏:固定在界面底部,保持左右拉伸即可。 + +![页面布局-布局基础案例-歌单详情页面布局能力360-800vp](figures/页面布局-布局基础案例-歌单详情页面布局能力360-800vp.png) + +在横竖屏切换时,完成了中尺寸和大尺寸的切换。歌单列表板块进行挪移的同时,内部采用了重复布局。 + +歌单信息和歌单操作板块因较小宽高比,挪移到上下排布。 + +![页面布局-布局基础案例-歌单详情页面布局能力800-1280vp](figures/页面布局-布局基础案例-歌单详情页面布局能力800-1280vp.png) + +当界面出现在智慧屏上,为了符合沉浸简约的设备信息和遥控器交互规则,将部分歌单信息替代原来标题栏的位置,并取消播放栏。同时歌单列表居左,更方便遥控器选择。 + +![页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp](figures/页面布局-布局基础案例-歌单详情页面布局能力1280-1920vp.png) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-components.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-controls.md similarity index 83% rename from zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-components.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-controls.md index e7596a093628bce8f7d217e4690bc2ec47df06aa..6693a67912b6d6afb7ec199c54cdfef44422a7ec 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-components.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-polymorphic-controls.md @@ -1,31 +1,36 @@ -# 多态控件 - - -为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。 - - -![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png) - - -多态控件应该具备以下特点: - - -- 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。 - -- 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。 - -- 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。 - - -## 控件的状态 - -- 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。 - -- 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。 - -常见的状态类型: - - | | | | -| -------- | -------- | -------- | -| ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)
**正常态**
表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)
**不可用态**
表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)
**点击态**
表明当前控件当前处于点击状态。
操作:手指或鼠标按下且未释放。 | -| ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)
**获焦态**
表明当前控件处于焦点状态。操作:
- 键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。
- 通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)
**激活态**
表明当前控件处于激活的状态。用于有多个元素可获焦的控件
操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)
**悬停态**
表明当前控件处于鼠标悬停的状态。
操作:将鼠标悬停在控件之上。 | +# 多态控件 + + +为了支持多设备,应用需要能够在不同的设备上运行,控件作为应用的基础组成部分,需要支持不同的设备,且在视觉、交互、动效等表现形式上针对设备进行必要的调整,达到最佳体验。因此,同一控件在不同的设备上会呈现出不同的形态,称为多态控件。 + + +![zh-cn_image_0000001268129090](figures/zh-cn_image_0000001268129090.png) + + +多态控件应该具备以下特点: + + +- 覆盖默认设备、平板,兼顾智慧屏、车机、智能穿戴等终端。 + +- 场景一致性。在对应的使用场景下,其交互、视觉、动效要保持一致,在设计上属性参数保持一致或差异化。 + +- 针对设备做优化。多态控件在不同的设备上的呈现应该是该设备下的最佳效果,因此在保证一致性的同时,还需要针对设备的特点进行优化。 + + +## 控件的状态 + +- 控件的状态是一种视觉呈现,用于展示控件当前处于何种交互阶段。不同控件的相同状态应该保持一致的视觉风格,且应该清晰可见。 + +- 应用可能部署在不同设备上供用户使用,有些设备会支持多种输入方式。例如平板可以连接蓝牙键盘和鼠标来做文字编辑工作,此时控件需要同时满足键盘和鼠标交互,需要支持获焦态和悬停态,如果控件没有支持这两种状态,在使用键盘走焦时或鼠标悬停时,控件就无法通过呈现出相应的状态为用户提供正确的视觉引导。OpenHarmony默认提供多种交互方式的控件实现,方便开发者支持多种输入方式和交互归一。 + +常见的状态类型: + +| | | | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001268288974](figures/zh-cn_image_0000001268288974.gif)
**正常态**
表明当前控件可交互。 | ![zh-cn_image_0000001268608890](figures/zh-cn_image_0000001268608890.gif)
**不可用态**
表明当前控件不可交互。一般使用灰显的方式呈现。 | ![zh-cn_image_0000001317208945](figures/zh-cn_image_0000001317208945.gif)
**点击态**
表明当前控件当前处于点击状态。
操作:手指或鼠标按下且未释放。 | +| ![zh-cn_image_0000001317488873](figures/zh-cn_image_0000001317488873.gif)
**获焦态**
表明当前控件处于焦点状态。操作:
- 键盘或遥控器通过方向键将焦点从一个控件移动到另外一个控件。
- 通过语音操作,使得控件获得焦点。 | ![zh-cn_image_0000001317089061](figures/zh-cn_image_0000001317089061.gif)
**激活态**
表明当前控件处于激活的状态。用于有多个元素可获焦的控件
操作:焦点处在页签控件的某个页签上时,该页签获焦。点击此页签,该页签被激活。 | ![zh-cn_image_0000001317328893](figures/zh-cn_image_0000001317328893.gif)
**悬停态**
表明当前控件处于鼠标悬停的状态。
操作:将鼠标悬停在控件之上。 | + + +## 弹出框 + +弹出框是一种模态窗口,在弹出框消失之前,用户无法操作其他界面内容,干扰性比较强。通常用来展示用户当前需要的或用户必须关注的信息或操作,其他情况不建议使用弹出框,可考虑通知等其他非模态窗口。 弹出框的内容通常是不同控件进行组合布局。例如文本(可带格式,如缩进、链接、粗体等)、列表、输入框、网格、图标或图片等,常用于选择或确认信息。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-principles.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-principles.md index 980ce34516ddc83b618201aa78249c68a54bea38..1079073aa98e16ab58cc454254b6de20b2f19c91 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/design-principles.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-principles.md @@ -19,7 +19,7 @@ **兼容性** -在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可以用、使用困难的问题。 +在硬件能力、交互方式、使用场景差异较大的设备上,除了考虑布局位置、内容宽度、横向组件数量,还需支持不同的输入方式、考虑功能架构的调整,避免出现输入不识别、功能不可用、使用困难的问题。 ## 设计要点 @@ -35,9 +35,9 @@ 例如:默认设备上的底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 提供了多种布局能力,开发者通过组合运用使内容 例如:默认设备上的滚动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中,边距、圆角、阴影、字体大小等,都可以通过参数来进行调整。 -![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默认提供支持多设备的控件,开发者可以直接使用并 | **以触控为主** | **以键鼠操作为主** | | -------- | -------- | | 下拉刷新 | 界面上提供“刷新”图标或适配F5快捷键 | -| 滑动多选 | 鼠标 框选 | +| 滑动多选 | 鼠标框选 | | 下拉关闭 | 界面上提供“关闭”图标 | | 长按浮起拖拽 | 鼠标直接拖拽 | diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/design-resources.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-resources.md new file mode 100644 index 0000000000000000000000000000000000000000..3a83dbeade1e5161f4c353bf7305fd0eeca27521 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-resources.md @@ -0,0 +1,30 @@ +# 资源 + + +为方便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及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。 + + +| 表格 | 简介 | +| -------- | -------- | +| 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 | +| 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 | +| 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 | +| 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 | +| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 | +| 不透明度数值速查表 | 用于将不透明度在**百分比表示形式**和**十六进制表示形式**之间快速转换的速查表。 | + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 推荐应用相关系统参数仅在应用开发场景中使用,卡片相关系统参数仅在卡片开发场景中使用。 +> +> - 同一系统参数在不同类型的设备上有不同的取值,当前仅提供了系统参数在默认设备上的取值,后续会针对不同设备类型做补充。 +> +> - 颜色可以用“RGB”或“ARGB”形式表示,采用“RGB”表示的颜色,完全不透明;采用“ARGB”表示的颜色,其不透明度由“A”(Alpha通道)确定。如“\#7FFF0000”代表不透明度为50%的红色,“\#FFFF0000”和“\#FF0000”都表示不透明度为100%(即完全不透明)的红色。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-responsive.md b/zh-cn/application-dev/key-features/multi-device-app-dev/design-responsive-layout.md similarity index 84% rename from zh-cn/application-dev/key-features/multi-device-app-dev/layout-responsive.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/design-responsive-layout.md index 2cfc87a761b6e6c34b01ebf619dac06bac614eaa..5e05d0f5c0c7d70192a58b8fffda9fa6d93179c1 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-responsive.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/design-responsive-layout.md @@ -1,51 +1,51 @@ -# 响应式布局 - - -当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。 - - -## 栅格断点系统 - -根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。 - -![zh-cn_image_0000001305864477](figures/zh-cn_image_0000001305864477.png) - -栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。 - -随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。 - - -## 缩进布局 - -为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。 - -![zh-cn_image_0000001264774952](figures/zh-cn_image_0000001264774952.gif) - -缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。 - -OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。 - - -## 挪移布局 - -利用屏幕的宽度优势,将原先的上下布局切换成左右布局。 - -例如,上下排布的插画和文字,横屏后左右排布。 - -![zh-cn_image_0000001264296340](figures/zh-cn_image_0000001264296340.gif) - -挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。 - - -## 重复布局 - -利用屏幕的宽度优势,将相同属性的组件横向并列排布。 - -![zh-cn_image_0000001306203573](figures/zh-cn_image_0000001306203573.gif) - -重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。 - -OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。 - - -响应式布局对应OpenHarmony系统提供的布局能力中的[栅格断点系统](grid-breakpoint.md)和[媒体查询](media-query.md),详见本文 “响应式布局”。 +# 响应式布局 + + +当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们需要针对不同终端的屏幕特点,设定容器与栅格的关系达到响应式的布局。通常响应式布局能根据栅格断点变化进行有级变化。 + + +## 栅格断点系统 + +根据设备的水平宽度,OpenHarmony提供了断点系统,覆盖超小、小、中、大 四种屏幕类型,并结合栅格系统默认提供了对应 Column 的数量关系。不同的设备根据自身屏幕水平宽度,在不同的断点范围,系统将自动匹配不同数量的栅格。应用也可针对具体界面自定义栅格。 + +![删格](figures/删格.png) + +栅格断点系统与日常使用的设备屏幕类型有一定的对应关系,例如:超小对应智能穿戴设备,小对应默认设备,中对应平板,大对应智慧屏与PC。设计师可面向希望运行的设备进行所属屏幕类型的适配。 + +随着智能设备种类的增加,越来越多产品在四种屏幕类型上具备不同的交互能力,如支持触摸的运动相机(小)、仅支持遥杆的手持云台(小-中)、不可移动的智能台灯(中-大)等,需结合具体设备交互进行对应设计,不可一概而论。 + + +## 缩进布局 + +为了在宽屏上内容显示有更好的效果,在不同宽度的设备上进行不同缩进效果。 + +![缩进布局](figures/缩进布局.gif) + +缩进适用于,因宽度明显变大,内容拉伸以后导致屏幕空白内容超过50%,或文本内容过长(每行大于30字),但没有上下级界面可供同时展示或上下级界面不适合同时显示的场景。 + +OpenHarmony提供的默认实现为,当栅格为8column或12column时可以响应6column和8column的缩进布局。 + + +## 挪移布局 + +利用屏幕的宽度优势,将原先的上下布局切换成左右布局。 + +例如,上下排布的插画和文字,横屏后左右排布。 + +![挪移布局](figures/挪移布局.gif) + +挪移布局适用于横竖屏切换,以及类似的宽高比明显变化(大于200%)同时希望保证内容完整的场景。 + + +## 重复布局 + +利用屏幕的宽度优势,将相同属性的组件横向并列排布。 + +![重复布局](figures/重复布局.gif) + +重复布局适用于对宽高比敏感的图片和及组合内容,当内容缩放以后导致原图放大超过150%的场景。 + +OpenHarmony栅格系统提供的分栏实现为,当栅格为8column或12column时可以将默认4栅格的页面整体进行重复布局。 + + +响应式布局对应OpenHarmony系统提供的布局能力中的栅格断点系统和媒体查询,详见本文 “[响应式布局](responsive-layout.md)”相关介绍。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/development-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/development-intro.md index 12553b47fadfa23a941f521ae9e443e4663299a1..4b67d2d5e3a66be2e0ac18f05ccf52ff2b9fd754 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/development-intro.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/development-intro.md @@ -1,82 +1,97 @@ -# 一多能力的功能开发介绍 - - -应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。 - - -我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。 - - -应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载->应用安装->应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路: - - -1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。 - -2. 安装:有NFC能力的设备才允许安装该应用。 - -3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。 - - -所以,对应的解决方案就有: - - -1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。 - -2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。 - -3. If/Else的动态逻辑判断。伪代码简单示例如下: - - ``` - if (该设备有系统能力1) { - 运行系统能力1相关的代码; - } else { - 提示用户该设备不支持; - } - ``` - - -OpenHarmony支持的设备类型分为两大类: - - -1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示: - ![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png) - - 或者module.json文件中的deviceTypes,如下图所示: - - ![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,中文名:要求的产品兼容性标识)。 - - -鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。 - - -## 编码时的API联想 - -IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下: - -![zh-cn_image_0000001267334018](figures/zh-cn_image_0000001267334018.gif) - - -## 动态逻辑判断 - -开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。 - - -``` -import geolocation from'@ohos.geolocation'; - const isLocationAvailable =canIUse('SystemCapability.Location.Location'); - if (isLocationAvailable) { - console.log('该设备支持位置信息'); - geolocation.getCurrentLocation((location) => { - console.log(location.latitude, location.longitude); - }) - } else { - console.log('该设备不支持位置信息'); - } -``` - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> 开发者通过 import 方式导入的模块,若当前设备不支持该模块,import 的结果为 undefined。故开发者在使用 API 时,需要判断其是否存在。 +# 功能开发的一多能力介绍 + + +应用开发至少包含两部分工作:UI页面开发和底层功能开发(部分需要联网的应用还会涉及服务端开发)。如“打开设备NFC”功能,除了开发页面,还需要调用系统API开启NFC。前面章节主要介绍了如何解决页面适配的问题,本章节主要介绍应用如何解决设备系统能力差异的兼容问题。 + + +我们以一个简单例子说明:一个具有NFC功能的应用,如何兼容运行在有NFC和无NFC系统能力的设备上。 + + +应用从开发到用户可以使用,一般要经历几个阶段:应用分发和下载->应用安装->应用运行,要解决上面提到的兼容问题,一般有如下几种解决思路: + + +1. 分发和下载:有NFC设备的用户才能在应用市场可见该应用,提供用户下载能力。 + +2. 安装:有NFC能力的设备才允许安装该应用。 + +3. 运行:在运行阶段通过动态判断方式,在NFC设备上功能运行正常,在无NFC设备上运行不发生Crash。 + + +所以,对应的解决方案就有: + + +1. 在分发阶段,核心分发逻辑:上架的应用使用的系统能力是设备系统能力的子集。满足这个条件,用户才能在应用市场看到该应用。 + +2. 在安装阶段,核心安装逻辑:安装的应用调用的系统能力是设备系统能力的子集。满足这个条件,用户才能安装该应用。 + +3. If/Else的动态逻辑判断。伪代码简单示例如下: + + ``` + if (该设备有系统能力1) { + 运行系统能力1相关的代码; + } else { + 提示用户该设备不支持; + } + ``` + + +OpenHarmony支持的设备类型分为两大类: + + +1. 典型设备类型,如默认设备、平板等。系统已经定义好了这些设备的系统能力集合,对应用开发者来说,只需要感知在IDE中创建Module时设备类型的选择,如下图所示: + ![zh-cn_image_0000001267573986](figures/zh-cn_image_0000001267573986.png) + + 或者module.json文件中的deviceTypes,如下图所示: + + ![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,中文名:要求的产品兼容性标识)。 + + +鉴于当前OpenHarmony版本还不具备设备认证中心,本章节仅讨论典型设备类型下多设备应用开发的场景。 + + +## 编码时的API联想 + +IDE中提供了API的联想功能,方便开发者使用系统能力。当开发者选择多个设备类型时,API的联想范围就是选择类型设备提供的API的并集,如同时支撑默认设备和平板,API的联想范围就是默认设备和平板支持的API的并集。API的联想效果如下: + +![Video_20220408101413](figures/Video_20220408101413.gif) + + +## 动态逻辑判断 + +开发者可以通过canIUse接口,判断目标设备是否支持某系统能力,进而执行不同的业务逻辑。 + + +``` +import geolocation from'@ohos.geolocation'; + +@Entry +@Component +struct Index { + @State message: string = 'unknown'; + aboutToAppear() { + if (canIUse('SystemCapability.Location.Location')) { + geolocation.getCurrentLocation().then((location) => { + this.message = 'current location: ' + JSON.stringify(location) + }) + } else { + this.message = 'This device does not have the ability to get location.' + } + } + + 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 时,需要判断其是否存在。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/faq.md b/zh-cn/application-dev/key-features/multi-device-app-dev/faq.md new file mode 100644 index 0000000000000000000000000000000000000000..20f4d2efd49f17330ca5c42a6b9d4c17d4fc4b6b --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/faq.md @@ -0,0 +1,181 @@ +# 常见问题 + + +## 如何查询设备类型 + +设备类型分为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 +# 取出开发板中的窗口配置文件,并将文件中的修改为 +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支持的最小的窗口宽度, 宽度单位为vp。 | +| minWindowHeight | 数值 | 标识该ability支持的最小的窗口高度, 高度单位为vp。 | +| maxWindowWidth | 数值 | 标识该ability支持的最大的窗口宽度,宽度单位为vp。 | +| maxWindowHeight | 数值 | 标识该ability支持的最大的窗口高度, 高度单位为vp。 | +| minWindowRatio | 数值 | 标识该ability支持的最小的宽高比。 | +| maxWindowRatio | 数值 | 标识该ability支持的最大的宽高比。 | + +如下所示,通过配置文件分别限制自由窗口的最大和最小尺寸。 + + +``` +{ + "module": { + ... + "abilities": [ + { + ... + "minWindowWidth": 320, + "minWindowHeight": 240, + "maxWindowWidth": 1440, + "maxWindowHeight": 900, + "minWindowRatio": 0.5, + "maxWindowRatio": 2, + } + ] + } +} +``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/faqs.md b/zh-cn/application-dev/key-features/multi-device-app-dev/faqs.md deleted file mode 100644 index 2ec8d05a98a6b9dbf03c151cc47800ad3e1d77dc..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/faqs.md +++ /dev/null @@ -1,111 +0,0 @@ -# 常见问题 - - -## 如何查询设备类型 - -设备类型分为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) **说明:** - > 通过窗口尺寸调整显示更加“可靠”,因为顶部状态栏、三键导航等可能占据部分屏幕空间,另外部分设备上的应用可能以窗口形式显示。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.3-2.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.3-2.png new file mode 100644 index 0000000000000000000000000000000000000000..61a66c3ba854dd98176ed31a3d247c744427de85 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.3-2.png differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\344\272\244\344\273\2304\344\273\266\345\245\227.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\344\272\244\344\273\2304\344\273\266\345\245\227.png" new file mode 100644 index 0000000000000000000000000000000000000000..fb7fbc7d9357e2f6ffe5adaf8925bb6095df1764 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\344\272\244\344\273\2304\344\273\266\345\245\227.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\210\207\345\233\276\350\265\204\346\272\220\345\257\271\345\272\224\346\226\207\344\273\266\345\244\271.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\210\207\345\233\276\350\265\204\346\272\220\345\257\271\345\272\224\346\226\207\344\273\266\345\244\271.png" new file mode 100644 index 0000000000000000000000000000000000000000..cf778edbe43256248a3b4aa3c67bf7ae5b6414e6 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\210\207\345\233\276\350\265\204\346\272\220\345\257\271\345\272\224\346\226\207\344\273\266\345\244\271.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\244\234\346\231\232\345\215\225\345\274\240\351\200\202\351\205\215\345\244\232\350\256\276\345\244\207.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\244\234\346\231\232\345\215\225\345\274\240\351\200\202\351\205\215\345\244\232\350\256\276\345\244\207.png" new file mode 100644 index 0000000000000000000000000000000000000000..e85a902f41ff00fa408d7c340bdc8ba7371c5ddc Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\345\244\234\346\231\232\345\215\225\345\274\240\351\200\202\351\205\215\345\244\232\350\256\276\345\244\207.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\225\210\346\236\234\347\244\272\346\204\217\345\233\276.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\225\210\346\236\234\347\244\272\346\204\217\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..04326bb88829e18cb51cd564e007b65809f7e5f3 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\225\210\346\236\234\347\244\272\346\204\217\345\233\276.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\231\264\345\244\251\345\244\232\345\274\240\351\200\202\351\205\215.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\231\264\345\244\251\345\244\232\345\274\240\351\200\202\351\205\215.png" new file mode 100644 index 0000000000000000000000000000000000000000..520a1c1d2db2f5877619b027db9d2229797c7d77 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\231\264\345\244\251\345\244\232\345\274\240\351\200\202\351\205\215.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\205\346\240\274\346\240\207\346\263\250.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\205\346\240\274\346\240\207\346\263\250.png" new file mode 100644 index 0000000000000000000000000000000000000000..858d077aefe1055217b5b922a9b68dfb579037c3 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\205\346\240\274\346\240\207\346\263\250.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\207\346\263\250\345\233\276.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\207\346\263\250\345\233\276.png" new file mode 100644 index 0000000000000000000000000000000000000000..b221e88e4a0b2132fa2002dccc43e6f5690c40d8 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/4.8-\346\240\207\346\263\250\345\233\276.png" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291670681.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/8vp.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291670681.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/8vp.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_lg_mark.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_lg_mark.png new file mode 100644 index 0000000000000000000000000000000000000000..4e86f1c1cd17f49bd9b2408808956a64f954a336 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_lg_mark.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_md_mark.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_md_mark.png new file mode 100644 index 0000000000000000000000000000000000000000..fa3e9e8740d0ad59fef73063686d598b5164e6c6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_md_mark.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_sm.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_sm.png new file mode 100644 index 0000000000000000000000000000000000000000..cb2de55e52f455c6170ddccf644d033977df08cb Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Home_sm.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_lg_running.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_lg_running.png new file mode 100644 index 0000000000000000000000000000000000000000..22fc98c18dc17b6715b9ef3e3e2a0ca9d3581842 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_lg_running.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_md_running.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_md_running.png new file mode 100644 index 0000000000000000000000000000000000000000..3c89355a41658806a11995c72706253f6e9bb343 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_md_running.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_sm_running.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_sm_running.png new file mode 100644 index 0000000000000000000000000000000000000000..85394fd934db82313cfcfbc272b90ac75832c6b3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/MusicAlbum_sm_running.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267334018.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/Video_20220408101413.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267334018.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/Video_20220408101413.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner1.PNG b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner1.PNG new file mode 100644 index 0000000000000000000000000000000000000000..ec94d9dc6657725d524896463d49ee8c70f97439 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner1.PNG differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner2.PNG b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner2.PNG new file mode 100644 index 0000000000000000000000000000000000000000..7bc364e2c7512f929d7a964df3b1cc48fd096ed7 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner2.PNG differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner3.PNG b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner3.PNG new file mode 100644 index 0000000000000000000000000000000000000000..8eea6e61d1ab70a3c58de38681a9bb48f8b466bc Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/banner3.PNG differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313602309.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/basic_guester.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313602309.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/basic_guester.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292656257.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/bottom_input_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292656257.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/bottom_input_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246337342.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/bottom_input_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246337342.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/bottom_input_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/component.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/component.gif new file mode 100644 index 0000000000000000000000000000000000000000..4bafc79316953a47ee6972c329109f9928eb5d2d Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/component.gif differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246816566.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/contact_details_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246816566.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/contact_details_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292777537.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/contact_details_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292777537.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/contact_details_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_lg.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_lg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..5b3986ac8476c13225418eb9f3a0b6df2941b0c4 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_lg.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_md.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_md.jpg new file mode 100644 index 0000000000000000000000000000000000000000..68a2602305b67254265107539a3ab9eb20e1cdfc Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_md.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_sm.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_sm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..73d988c4bf398a10f27b3ce3ae9bff5f5f83f038 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/diversion_sm.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/home_full.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/home_full.png new file mode 100644 index 0000000000000000000000000000000000000000..3723f1ad1f037418252d22b440773ee42ab1e22e Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/home_full.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220820153523548.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220820153523548.png new file mode 100644 index 0000000000000000000000000000000000000000..c3312b86ffacd672c562635588d963a18905a5d0 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220820153523548.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922185907892.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922185907892.png new file mode 100644 index 0000000000000000000000000000000000000000..d4c09a794a2375258af0a4d4d03573b62fff18c0 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922185907892.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922190217247.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922190217247.png new file mode 100644 index 0000000000000000000000000000000000000000..42545e0cec868a5b1f2f8759e98952ffa632558a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/image-20220922190217247.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img2.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img2.png new file mode 100644 index 0000000000000000000000000000000000000000..8cb7de4c9eea4d64de274ffdda68db5ea271667a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img2.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img3.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img3.png new file mode 100644 index 0000000000000000000000000000000000000000..6999333acd811085cad6f0e8c4d2356de79b751f Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img3.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img4.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img4.png new file mode 100644 index 0000000000000000000000000000000000000000..9d1d8b8171c0957dbc1ae90d15efa9537aa9ad30 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/img4.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_lg.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_lg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7a042787c5a11fa2736c669f04a92737a8697e81 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_lg.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_md.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_md.jpg new file mode 100644 index 0000000000000000000000000000000000000000..98c0154736ad08bbd897bb57e379613f597ec276 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_md.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_sm.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_sm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..86753296d05e1b13a115922ff1b60fe5520bef4a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/indent_sm.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/lg.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/lg.png new file mode 100644 index 0000000000000000000000000000000000000000..897980134ccc7b6b06217600f36c8bc3229683d9 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/lg.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/md.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/md.png new file mode 100644 index 0000000000000000000000000000000000000000..713274e95063af3463b25d333e79b75a1483db16 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/md.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313844881.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_basic_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313844881.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_basic_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313724825.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_basic_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313724825.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_basic_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313604829.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_radius_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313604829.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_radius_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313523845.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_radius_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313523845.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_radius_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266163748.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_recv_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266163748.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_recv_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001265685020.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_recv_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001265685020.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_recv_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001265844904.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_send_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001265844904.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_send_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266004832.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_send_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266004832.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_bubble_send_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313844889.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_list_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313844889.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_list_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313724829.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_list_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313724829.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/message_list_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315500981.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/multi_device.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315500981.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/multi_device.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225812214.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/overview_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225812214.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/overview_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225486054.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/overview_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225486054.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/overview_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/previewer.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/previewer.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9423543bf57b5d9374ddb825925488c4fe7d869a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/previewer.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/project.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/project.png new file mode 100644 index 0000000000000000000000000000000000000000..23e664278123958a14fe7e5238a141f3118bb427 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/project.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_lg.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_lg.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a8bc3d00a133c414aa5f11287c71cc0c74c9be6a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_lg.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_md.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_md.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bddc83f93e3afe3d9a4a231d6d58665d75d318eb Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_md.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_sm.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_sm.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1120cd4e6e1d2e384ada80e5f4517accc4c3f523 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/repeat_sm.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/sm.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/sm.png new file mode 100644 index 0000000000000000000000000000000000000000..29f89209d46057c76440e307e5b44caf31b7096b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/sm.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292777233.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_blank_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292777233.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_blank_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246497370.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_blank_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246497370.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_blank_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001293015965.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_done_phone.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001293015965.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_done_phone.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246656958.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_done_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001246656958.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_done_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225486202.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_tablet.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225486202.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/top_title_tablet.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/window3.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/window3.gif new file mode 100644 index 0000000000000000000000000000000000000000..0ee4358e2a3aca5ca9129e79ad5a615958e81087 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/window3.gif differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225809618.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225809618.png deleted file mode 100644 index eb646f495caa2a1c82f5cb13edf67741c9a59454..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001225809618.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226091264.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226091264.jpg deleted file mode 100644 index ed8dfb6a49ff732daff1545932f97696c276a6f3..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226091264.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245276368.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245276368.png deleted file mode 100644 index adb7dddc1a86973ffc8f95bbdf33f9fc4a42a79b..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245276368.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245456434.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245456434.jpg deleted file mode 100644 index d3f4c6cd9594ea9ce07506bbd4000d30c5e62dcd..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245456434.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266893124.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266893124.jpg deleted file mode 100644 index c60e618b59cefd5c8c5ac7ff63df35113d3ce7ca..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266893124.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293008.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293008.jpg deleted file mode 100644 index 882da39255c1d6250a13bbb0ee26d7b376662cdd..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293008.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293016.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293016.jpg deleted file mode 100644 index 66c3abb8134dd051232f4502c2b85c9efb9affd1..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267293016.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267532988.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267532988.jpg deleted file mode 100644 index e7ec6327c9e4922d46fe46286e77e8433298507a..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267532988.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932928.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932928.jpg deleted file mode 100644 index b200a33d9e1c4fdc46ce6e46d6c1f22e7d48a53e..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932928.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932936.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932936.jpg deleted file mode 100644 index 24c27cab9131496a19fddc28b13ac5568ba3b89c..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267932936.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268288870.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268288870.png deleted file mode 100644 index e99d02e3179759ea105bca2c3e2b3cce4f8cc19b..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268288870.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268608782.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268608782.png deleted file mode 100644 index 8846dfd20ad6b1734bd9e5f4a12a9386e35751f7..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268608782.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268611858.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268611858.png deleted file mode 100644 index 6311d889fa44033f8043f256763d27f53ff98fcd..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268611858.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001269812713.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001269812713.png deleted file mode 100644 index abfc4957f22fd2a252397928d3da459ff6790db8..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001269812713.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270045849.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270045849.png deleted file mode 100644 index aacb2d0e32a4ba415ae26311a37c72fbefe500d5..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270045849.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292375365.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292375365.png deleted file mode 100644 index cccb36a1219a5c5b9800139cfde238d9db80841a..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292375365.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292842113.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292842113.gif deleted file mode 100644 index b2477d1a4ef1fa102f553e510d97a7623c35344b..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292842113.gif and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313517281.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313517281.png new file mode 100644 index 0000000000000000000000000000000000000000..23ef4160b4f363d512d317ef85ca4788b7dcc0d4 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313517281.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315453085.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315453085.jpg deleted file mode 100644 index 0a9da648084ce61ec83dc839c4e0eb1daca0d8a6..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315453085.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315732933.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315732933.jpg deleted file mode 100644 index 567ecd5023d4d6b489878f2ab82842c7ccac8ca8..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315732933.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932969.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932969.jpg deleted file mode 100644 index b0efc989a400455569438f84c644f1a789f48e50..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932969.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932977.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932977.jpg deleted file mode 100644 index d6322f40d6ac16f6eaf310523b3d40ca4a445dd7..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001315932977.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932917.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932917.jpg deleted file mode 100644 index e77b5505da096e4e1290cb2b510ba579565d9213..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932917.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932929.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932929.jpg deleted file mode 100644 index c481fcf532955973f8f5c3293c519de3d6f069a8..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001316932929.jpg and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317085757.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317085757.png deleted file mode 100644 index 71ff9d4c145e248b5e17a06e931c9678c286de50..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317085757.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317091985.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317091985.png deleted file mode 100644 index c8ea88a7443694ceb213aff5462cd1997e8ff2f3..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317091985.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317208833.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317208833.png deleted file mode 100644 index 074f33a3cbaeb050c156ed6f603778ac1591c360..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317208833.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317211889.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317211889.png deleted file mode 100644 index 2c4382b148b2177db14b4210c3bba6ddc999f73d..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317211889.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317848113.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317848113.png deleted file mode 100644 index 08f1ea1d884aad4a97465436377c1b1755c7c68b..0000000000000000000000000000000000000000 Binary files a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317848113.png and /dev/null differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267577314.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001325731389.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001267577314.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001325731389.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259918.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259918.png new file mode 100644 index 0000000000000000000000000000000000000000..160f9a91934d7ff38576e6d45742f36f38026881 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259918.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259922.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259922.png new file mode 100644 index 0000000000000000000000000000000000000000..62772d441c10a7930eec3ae76af86db58f7727a2 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328259922.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328579522.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328579522.png new file mode 100644 index 0000000000000000000000000000000000000000..6a7a496926fe88627261c41695bca3f9523ce3a3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328579522.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328745102.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328745102.png new file mode 100644 index 0000000000000000000000000000000000000000..ae7c4ba354b0b5cdb8859750e9f5bb101f5aafb4 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001328745102.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329658136.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329658136.png new file mode 100644 index 0000000000000000000000000000000000000000..2ccd21cbb363b62e02130207b1b2fbb447a8a8e5 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329658136.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329660244.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329660244.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b786a8de51a2a8fb466ef7f36bc80a830a6d64a4 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329660244.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329666380.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329666380.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d39dfd99b338c94807f405bb3aff3bfea245743a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329666380.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329813432.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329813432.png new file mode 100644 index 0000000000000000000000000000000000000000..e7136812c230f29c239f093fd0fb776913b385a7 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329813432.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329817776.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329817776.png new file mode 100644 index 0000000000000000000000000000000000000000..f0887bae74638e49d59ff423d0ce213e694bb05e Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329817776.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329977740.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329977740.png new file mode 100644 index 0000000000000000000000000000000000000000..dee703f8aa7f6c0e28cdd5b1dead2ce911e36909 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001329977740.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330133330.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330133330.jpg new file mode 100644 index 0000000000000000000000000000000000000000..80e69bc08ed4eaad1b28b7c1e48bdf12a46d956e Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330133330.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330137692.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330137692.png new file mode 100644 index 0000000000000000000000000000000000000000..a193bc62457c7d15a2f03044b67831b82cb65b88 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330137692.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330145976.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330145976.png new file mode 100644 index 0000000000000000000000000000000000000000..cd343d419f0cba653fae9b74220bbb2d847d6f9a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001330145976.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334020938.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334020938.png new file mode 100644 index 0000000000000000000000000000000000000000..ee5c5bb40e84443c88351e726a1298a9d624555f Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334020938.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334340566.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334340566.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e2ddf00fcb6771eaf4f8e3d5cad25cee133f8f98 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334340566.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334345550.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334345550.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bc3592dd452047ca2c896783f8718619a106d08b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001334345550.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266042114.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335316714.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001266042114.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335316714.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001285597989.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335380378.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001285597989.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335380378.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291935425.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335477142.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291935425.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335477142.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245136646.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335485154.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245136646.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335485154.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268450593.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335539986.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268450593.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335539986.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245614634.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335640862.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245614634.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335640862.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245295918.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335641246.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245295918.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335641246.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224250350.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335699774.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224250350.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335699774.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245613530.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335796258.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245613530.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001335796258.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336008356.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336008356.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2162910ba9c1b3afeee5e9bb09fb62ce30fb5a5c Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336008356.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336019094.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336019094.jpg new file mode 100644 index 0000000000000000000000000000000000000000..79870b5b687ccd9689637cefa9b50cd93b352258 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336019094.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336165712.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336165712.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3b097af224f3cad8cf5228f5f36d903651828583 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336165712.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336167540.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336167540.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f9b262d909d8ae30abfca4bf47d294686b69e7f5 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336167540.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336168020.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336168020.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9f4fa879024906d5afa8dacb242fc0c1bfb83511 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336168020.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327452.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327452.png new file mode 100644 index 0000000000000000000000000000000000000000..1e1e9685a267abc571e69c2298b0c530e930f36b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327452.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327916.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327916.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4871e601fadeb19eb2dc28398fe0db7cd36375df Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336327916.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336338670.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336338670.jpg new file mode 100644 index 0000000000000000000000000000000000000000..4e5299996f3c741b0fa3a6b12c9a24fd566aee1c Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336338670.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336485520.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336485520.jpg new file mode 100644 index 0000000000000000000000000000000000000000..edae3ef8d20a6bb96a145c66a31ba6065b4d290f Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336485520.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336486244.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336486244.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25dc94ad55aeb7ce1169e34a477f4b1f0a3f4838 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336486244.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487884.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487884.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ad981c83edb9cad570a4d341710e93c3f3879776 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487884.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487888.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487888.jpg new file mode 100644 index 0000000000000000000000000000000000000000..1a74880c551b9e1f3a0cf3b53908a0336589d5d3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336487888.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336498646.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336498646.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a4ca862c3f5a7ca7f775b8cae3c7a907dc9a89f5 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001336498646.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001344993822.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001344993822.jpg new file mode 100644 index 0000000000000000000000000000000000000000..306a92d9a850c9f100a18884c8006ff47514770d Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001344993822.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345312038.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345312038.png new file mode 100644 index 0000000000000000000000000000000000000000..e3a2ab0cec7c920b0804878b62e5e705bddff8ef Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345312038.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345473362.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345473362.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e61712e6eef5fccb1fe62f46a70b22027b0fd3f3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001345473362.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001348546856.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001348546856.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8bb83ec7f6a9712c3505ec5d10279768e4ca6863 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001348546856.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001349454550.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001349454550.png new file mode 100644 index 0000000000000000000000000000000000000000..377ae17a385b37b65a927296b8100fa57287400a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001349454550.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001223973996.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001350234552.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001223973996.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001350234552.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179861.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179861.png new file mode 100644 index 0000000000000000000000000000000000000000..8d0308bb4f3b2ab3a9edffb0866c0d668e5cc4c6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179861.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179865.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179865.png new file mode 100644 index 0000000000000000000000000000000000000000..581e2d69c3c3436e9cd748107a1e9edabfdece72 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379179865.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379299533.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379299533.png new file mode 100644 index 0000000000000000000000000000000000000000..284d0e3d6a27dc9fd46ad52487162b44c91bb8e6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379299533.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379385785.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379385785.png new file mode 100644 index 0000000000000000000000000000000000000000..65fb2f59626488acfeeacc587ab6c5573473ad0b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379385785.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464977.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464977.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9d5fae063702409f8030b69540ffc7d9ddc1bb60 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464977.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464981.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464981.png new file mode 100644 index 0000000000000000000000000000000000000000..d2b6907b2dbb9f6763e480f84158eb90fec080e3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001379464981.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001380933349.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001380933349.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e168c141e69656b9059671d192281e8c4ec43df6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001380933349.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013985.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013985.png new file mode 100644 index 0000000000000000000000000000000000000000..50c9f7467c8607c1494c0799b28550990f0da5d6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013985.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013989.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013989.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a9beca8b4e7064f7765aaad54f9b4bbaa77dc935 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381013989.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381018337.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381018337.png new file mode 100644 index 0000000000000000000000000000000000000000..e75e4b289d7479f5c17fbfa87b38ae5036426ddc Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381018337.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381026609.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381026609.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cd3f9eb4afce410b804665985332b85f17a921f6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381026609.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381133197.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381133197.png new file mode 100644 index 0000000000000000000000000000000000000000..8e369a882f4be86ff4ae97c07abf439487c11253 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381133197.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381137517.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381137517.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3ded0480ef2c4e36797b436a8275814dc3bdd622 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381137517.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381145789.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381145789.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e79fce0014ef51a01da3ff08d82f3c726c33da85 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381145789.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220165.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220165.png new file mode 100644 index 0000000000000000000000000000000000000000..224c3f6786e3b9e7e4c3a229d66fe85c556e6eda Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220165.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220169.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220169.png new file mode 100644 index 0000000000000000000000000000000000000000..49846845ca794c645a7ee12af2808bb08f4b5ffa Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381220169.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381226321.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381226321.png new file mode 100644 index 0000000000000000000000000000000000000000..b39e7cc81083549c8bb920310d4b1a79865d11bc Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381226321.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381379829.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381379829.png new file mode 100644 index 0000000000000000000000000000000000000000..ab02d8aded9684bb990c68d7b851bff24850c01e Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381379829.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381385985.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381385985.png new file mode 100644 index 0000000000000000000000000000000000000000..6dd26f5d918cd9b3c15df707ebd6c61260e27086 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001381385985.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384621049.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384621049.jpg new file mode 100644 index 0000000000000000000000000000000000000000..82843126e752d14df1142ccd676d7d7cdda35a52 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384621049.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384985569.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384985569.jpg new file mode 100644 index 0000000000000000000000000000000000000000..210046bd10dfb9e893c667b33dc6f52b496525f3 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001384985569.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385100509.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385100509.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e4609cb43bb45f0f42692d8284336c7ec224e146 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385100509.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385105477.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385105477.jpg new file mode 100644 index 0000000000000000000000000000000000000000..03562e2205dbf370ee9f1c27017516585197164a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385105477.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385380457.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385380457.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6f4af2c2400c66c96643786dfd3b1c97041f2c15 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385380457.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292215677.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385645821.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292215677.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385645821.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292374353.gif b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385757965.gif similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292374353.gif rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001385757965.gif diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268490361.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386060209.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268490361.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386060209.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268250529.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386179873.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268250529.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386179873.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224250574.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386180233.jpg similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224250574.jpg rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386180233.jpg diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386325621.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386325621.jpg new file mode 100644 index 0000000000000000000000000000000000000000..94fdba956de23737e887f779015325b7c049e092 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386325621.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386327997.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386327997.jpg new file mode 100644 index 0000000000000000000000000000000000000000..af26fcbf8d5e0769cb20bf0ad67dd908007feeca Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386327997.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386328001.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386328001.jpg new file mode 100644 index 0000000000000000000000000000000000000000..2709ecdf86b419382c691d05bf494c028479f8c6 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386328001.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386485617.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386485617.jpg new file mode 100644 index 0000000000000000000000000000000000000000..b9cb6d5d1874aa846e53484a65ea3529a166eddf Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386485617.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487457.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487457.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f85393c923a1982d7977d307caa1e7fdce15f67b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487457.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487913.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487913.jpg new file mode 100644 index 0000000000000000000000000000000000000000..21f196465685b5720eb604285b1651c1ce61d94a Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386487913.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386645965.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386645965.jpg new file mode 100644 index 0000000000000000000000000000000000000000..abd781a0e079d083853a63f7b409bb172adaeddd Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386645965.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386646685.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386646685.jpg new file mode 100644 index 0000000000000000000000000000000000000000..a787f38f2f847d53a66fc5af8e8749a3f6b58444 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386646685.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648317.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648317.jpg new file mode 100644 index 0000000000000000000000000000000000000000..07ff703de8ffc835b4a142ce9948c97739178497 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648317.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648321.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648321.jpg new file mode 100644 index 0000000000000000000000000000000000000000..61e3405eeaea5a37e287bbe6e8bcdd109210994c Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386648321.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386805569.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386805569.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f8b1e0c2a620555501b81d5bc06f7a09473ce65d Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386805569.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807405.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807405.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9234cb07b235b5eb9076e293f0c058da8981722c Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807405.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807873.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807873.jpg new file mode 100644 index 0000000000000000000000000000000000000000..65d050066ca046e87ed1da70c550e4bc7f121a55 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807873.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807877.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807877.jpg new file mode 100644 index 0000000000000000000000000000000000000000..df47760994b40272dcec3eaa27a15d1b56b9318e Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001386807877.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395631821.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395631821.png new file mode 100644 index 0000000000000000000000000000000000000000..b8b6222db6eb6fe1a1e2218380f346a10782d57b Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395631821.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395713305.jpg b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395713305.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6329657197acb876e02438e605ece87afd2e130f Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001395713305.jpg differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400300617.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400300617.png new file mode 100644 index 0000000000000000000000000000000000000000..0f193d141fe370441c9c5d66c2f5fb3eae122cbd Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400300617.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268654109.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400554657.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268654109.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400554657.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400662385.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400662385.png new file mode 100644 index 0000000000000000000000000000000000000000..0ad81c84e69a61f85f61162d53fa9bbeacfbd083 Binary files /dev/null and b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400662385.png differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224333892.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400674189.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001224333892.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400674189.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001223973992.png b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400874297.png similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001223973992.png rename to zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001400874297.png diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325609.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-1-1.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325609.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-1-1.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226444718.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-2.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226444718.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-2.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270924709.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-3.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270924709.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-3.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270804909.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-5.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001270804909.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-5.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226124842.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-6.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001226124842.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-2-6.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317088945.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2001.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317088945.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2001.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317328797.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2002.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317328797.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2002.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268448854.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2003.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268448854.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\270\203\345\261\2003.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317205645.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\205\263\344\272\216.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317205645.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\205\263\344\272\216.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268605598.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\210\227\350\241\250\350\247\206\350\247\211\345\233\276.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268605598.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\210\227\350\241\250\350\247\206\350\247\211\345\233\276.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317205637.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\220\257\345\212\250\351\241\265.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317205637.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\345\220\257\345\212\250\351\241\265.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317085761.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\346\210\221\347\232\204\351\241\265\351\235\242.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317085761.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\346\210\221\347\232\204\351\241\265\351\235\242.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485577.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\347\251\272\351\241\265\351\235\242.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485577.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\347\251\272\351\241\265\351\235\242.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268445650.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\347\275\221\346\240\274\350\247\206\345\233\276.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268445650.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\347\275\221\346\240\274\350\247\206\345\233\276.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325617.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\247\206\351\242\221\346\222\255\346\224\276.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325617.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\247\206\351\242\221\346\222\255\346\224\276.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268125814.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\247\206\351\242\221\350\257\246\346\203\205.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268125814.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\247\206\351\242\221\350\257\246\346\203\205.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268285682.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\256\276\347\275\256.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268285682.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\345\272\224\347\224\250\346\236\266\346\236\204-\350\256\276\347\275\256.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485573.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\346\246\202\350\277\260-\347\225\214\351\235\242\345\270\203\345\261\200-banner\344\276\213\345\233\276.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485573.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\270\200\345\244\232-\346\246\202\350\277\260-\347\225\214\351\235\242\345\270\203\345\261\200-banner\344\276\213\345\233\276.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313720673.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\275\215\345\233\27621.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001313720673.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\344\275\215\345\233\27621.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001305864477.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\210\240\346\240\274.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001305864477.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\210\240\346\240\274.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291556325.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\235\207\345\210\206\350\203\275\345\212\233.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291556325.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\235\207\345\210\206\350\203\275\345\212\233.gif" diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250matePadPro.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250matePadPro.png" new file mode 100644 index 0000000000000000000000000000000000000000..d2ff5d374b183bb29d3d8e9e87777ce7e5960718 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250matePadPro.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\211\213\346\234\272.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\211\213\346\234\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..7259d6a34ba16f167f36bdf19cf2de100d21bbe1 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\211\213\346\234\272.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\212\230\345\217\240\345\261\217.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\212\230\345\217\240\345\261\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..a668c322988c9978ae4d0acba70f745b2ec4b319 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\232\345\210\227\345\210\227\350\241\250\346\212\230\345\217\240\345\261\217.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210matePadPRo.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210matePadPRo.png" new file mode 100644 index 0000000000000000000000000000000000000000..34989d3fce6e82c1887049149478467eb1b73f0b Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210matePadPRo.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\211\213\346\234\272.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\211\213\346\234\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..85b5aa99c2357fc95dabc78d9e6e43226bcfeb16 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\211\213\346\234\272.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\212\230\345\217\240\345\261\217.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\212\230\345\217\240\345\261\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..ae0ef3a1c83f9b9d1cd161c0523d423659080d75 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\244\247\345\233\276\346\265\217\350\247\210\346\212\230\345\217\240\345\261\217.png" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292686089.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\255\227\344\275\223copy2.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001292686089.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\255\227\344\275\223copy2.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268128998.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\345\261\202\347\272\247\345\257\274\350\210\252-\350\256\276\347\275\256.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268128998.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\345\261\202\347\272\247\345\257\274\350\210\252-\350\256\276\347\275\256.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268445654.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\236\202\347\261\273\351\241\265\351\235\242\347\273\223\346\236\204-\346\255\214\345\215\225\350\257\246\346\203\205\344\275\216\344\277\235\347\234\237.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268445654.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\236\202\347\261\273\351\241\265\351\235\242\347\273\223\346\236\204-\346\255\214\345\215\225\350\257\246\346\203\205\344\275\216\344\277\235\347\234\237.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268605602.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\236\202\347\261\273\351\241\265\351\235\242\347\273\223\346\236\204-\351\237\263\344\271\220\346\222\255\346\224\276\344\275\216\344\277\235\347\234\237.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268605602.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\236\202\347\261\273\351\241\265\351\235\242\347\273\223\346\236\204-\351\237\263\344\271\220\346\222\255\346\224\276\344\275\216\344\277\235\347\234\237.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268125810.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\351\200\232\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\244\232\351\200\211\351\241\265\351\235\242\344\275\216\344\277\235\347\234\237.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268125810.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\351\200\232\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\345\244\232\351\200\211\351\241\265\351\235\242\344\275\216\344\277\235\347\234\237.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325613.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\351\200\232\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\350\257\246\346\203\205\351\241\265\351\235\242\344\275\216\344\277\235\347\234\237.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317325613.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\272\224\347\224\250\346\236\266\346\236\204-\345\270\270\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\351\200\232\347\224\250\351\241\265\351\235\242\347\273\223\346\236\204-\350\257\246\346\203\205\351\241\265\351\235\242\344\275\216\344\277\235\347\234\237.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291556369.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\273\266\351\225\277\350\203\275\345\212\233.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291556369.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\345\273\266\351\225\277\350\203\275\345\212\233.gif" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291675805.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\212\230\350\241\214\346\241\210\344\276\213\345\210\206\351\225\234.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001291675805.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\212\230\350\241\214\346\241\210\344\276\213\345\210\206\351\225\234.png" diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\213\211\344\274\270\346\263\250\346\204\217\345\234\272\346\231\257.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\213\211\344\274\270\346\263\250\346\204\217\345\234\272\346\231\257.png" new file mode 100644 index 0000000000000000000000000000000000000000..cf2de1d9bc8446cee411fa6348459c6775bcfb54 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\213\211\344\274\270\346\263\250\346\204\217\345\234\272\346\231\257.png" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001258762686.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\213\211\344\274\270\350\203\275\345\212\233.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001258762686.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\213\211\344\274\270\350\203\275\345\212\233.gif" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001264296340.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\214\252\347\247\273\345\270\203\345\261\200.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001264296340.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\214\252\347\247\273\345\270\203\345\261\200.gif" diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243matePadPro.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243matePadPro.png" new file mode 100644 index 0000000000000000000000000000000000000000..5214a9e6f6cbeb2f3e74d0964d340cbfe64aaa10 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243matePadPro.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\211\213\346\234\272.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\211\213\346\234\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..8506c9f756660b4502caf09d9e1c7b8ca5d5d0a0 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\211\213\346\234\272.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\212\230\345\217\240\345\261\217.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\212\230\345\217\240\345\261\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..199dc886a28b45f8e2c67259a6ffdb9af753a647 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\223\215\344\275\234\345\205\245\345\217\243\346\212\230\345\217\240\345\261\217.png" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001305734113.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\240\205\346\240\274\347\263\273\347\273\237\344\276\213.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001305734113.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\240\205\346\240\274\347\263\273\347\273\237\344\276\213.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268285678.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\246\202\350\277\260-\347\225\214\351\235\242\345\270\203\345\261\200-\346\255\214\345\215\225\350\257\246\346\203\205\351\253\230\344\277\235\347\234\237.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001268285678.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\246\202\350\277\260-\347\225\214\351\235\242\345\270\203\345\261\200-\346\255\214\345\215\225\350\257\246\346\203\205\351\253\230\344\277\235\347\234\237.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001263489242.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\267\267\345\220\210\345\257\274\350\210\252.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001263489242.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\346\267\267\345\220\210\345\257\274\350\210\252.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485581.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\211\271\346\256\212\351\241\265\351\235\242\347\273\223\346\236\204.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001317485581.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\211\271\346\256\212\351\241\265\351\235\242\347\273\223\346\236\204.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001251153442.png "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\224\273\346\235\277copy.png" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001251153442.png rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\224\273\346\235\277copy.png" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245116688.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\274\251\346\224\276\346\241\210\344\276\213.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245116688.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\274\251\346\224\276\346\241\210\344\276\213.gif" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001264774952.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\274\251\350\277\233\345\270\203\345\261\200.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001264774952.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\347\274\251\350\277\233\345\270\203\345\261\200.gif" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001306203573.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\207\215\345\244\215\345\270\203\345\261\200.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001306203573.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\207\215\345\244\215\345\270\203\345\261\200.gif" diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245276416.gif "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\232\220\350\227\217\350\203\275\345\212\233.gif" similarity index 100% rename from zh-cn/application-dev/key-features/multi-device-app-dev/figures/zh-cn_image_0000001245276416.gif rename to "zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\232\220\350\227\217\350\203\275\345\212\233.gif" diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200matePadPro.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200matePadPro.png" new file mode 100644 index 0000000000000000000000000000000000000000..919ae8d1ad167ce7ccfa584e62d9c3fa9f9061a3 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200matePadPro.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\211\213\346\234\272.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\211\213\346\234\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..afb189d20b5abb9da4120ef16045fcfeffc4b052 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\211\213\346\234\272.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..4893dc9d082b66117aa063df965d1ef962613d7a Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\347\255\276\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\2331280-1920vp.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\2331280-1920vp.png" new file mode 100644 index 0000000000000000000000000000000000000000..5fdd581c45463ea4aa53236358bd02fec0f1d198 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\2331280-1920vp.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233360-800vp.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233360-800vp.png" new file mode 100644 index 0000000000000000000000000000000000000000..2d1e85d22361ca8806c40794bd5589fb5e703c12 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233360-800vp.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233800-1280vp.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233800-1280vp.png" new file mode 100644 index 0000000000000000000000000000000000000000..c8a3650fbadbde3d091c3cc3dcd8f9c47ecaf79d Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\265\351\235\242\345\270\203\345\261\200-\345\270\203\345\261\200\345\237\272\347\241\200\346\241\210\344\276\213-\346\255\214\345\215\225\350\257\246\346\203\205\351\241\265\351\235\242\345\270\203\345\261\200\350\203\275\345\212\233800-1280vp.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200matePadPro.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200matePadPro.png" new file mode 100644 index 0000000000000000000000000000000000000000..2ca239cb81d0ba390b9df1e4b2391d7d3c0579a2 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200matePadPro.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\211\213\346\234\272.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\211\213\346\234\272.png" new file mode 100644 index 0000000000000000000000000000000000000000..c9f13ab60d96d786839dbe835edc428bb1cd802a Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\211\213\346\234\272.png" differ diff --git "a/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" new file mode 100644 index 0000000000000000000000000000000000000000..08cf6b0bc64a1bb4eec19ecef559b5274c976302 Binary files /dev/null and "b/zh-cn/application-dev/key-features/multi-device-app-dev/figures/\351\241\266\351\203\250\345\270\203\345\261\200\346\212\230\345\217\240\345\261\217.png" differ diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/foreword.md b/zh-cn/application-dev/key-features/multi-device-app-dev/foreword.md new file mode 100644 index 0000000000000000000000000000000000000000..8f2e9a395ee62ac1c95abd5c7783ba24f6a82526 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/foreword.md @@ -0,0 +1,48 @@ +# 前言 + + +本文介绍了“一次开发,多端部署”(后文中简称为“一多”)的定义、目标等,同时从UX设计、工程管理、页面开发、功能开发等角度,端到端的给出了指导,帮助开发者快速开发出适配多种类型设备的应用。在应用开发前,开发者应尽可能全面考虑应用支持多设备的情况,避免在后期加入新的类型设备时对应用架构进行大幅调整。 + + +## 本文面向的读者 + +本文适合开发OpenHarmony应用的UX设计师及开发人员。当然,也欢迎任何对“一多”感兴趣的读者阅读本文,相信读者们都可以从中获益。 + +推荐尽量按照章节顺序阅读本文。如果时间有限,按照角色区分,建议至少阅读如下章节: + +- UX设计师:第2章、第3章、第4章。 + +- 开发人员:第2章、第3章、第5章、第6章、第7章。 + + +## 章节概要 + +应用在需求明确后,开发过程大致分为:应用设计(包含界面UX设计、业务功能设计)->工程设计和创建->功能代码实现。本指导也是基于这个流程进行的内容编排。 + +本文档各章节简介如下: + +- 第1章前言说明本文的目的以及本文面向的读者,指引读者更好地阅读。 + +- 第2章[简介](introduction.md)简短介绍了“一多”的背景、定义、目标、以及用于指导后续开发的一些基础知识。 + +- 第3章[从一个例子开始](start-with-a-example.md)通过示例介绍“一多”应用的开发过程,让读者对“一多”有个直观认识。 + +- 第4章[应用UX设计](design-principles.md)介绍了应用UX设计理念。主要阐述了应用设计之初UX设计的原则和要点。该章节主要面向应用的UX设计师。 + UX设计原则应该考虑多设备的“差异性” 、“一致性”、“灵活性”和“兼容性”。 + + UX设计要点则从6个方面阐述如何进行多设备应用设计,分别是“自适应应用架构”、“响应式界面布局”、“交互归一”、“视觉参数化”、“多态控件”和“针对性优化”。 + + 最后,给出设计自检表,用于检查应用UX设计是否合理 。 + +- 第5章[工程管理](ide-using.md)介绍了从工程角度如何开始开发应用,让读者可以直接上手创建多设备应用的工程,是后面学习“一多”能力的上手基础。 + +- 第6章[页面开发的一多能力介绍](page-development-intro.md)和第7章[功能开发的一多能力介绍](development-intro.md)介绍了OpenHarmony提供的“一多”能力,其中每个能力都提供了代码示例和UX效果,让读者可以快速学习“一多”能力。 + +- 第8章[案例应用](case.md)阐述了从应用设计到开发这一过程中如何实践前面章节介绍的设计思路或“一多”能力,让读者可以整体掌握“一多”在应用开发过程中的知识。 + +- 第9章[常见问题](faq.md)提供了常见的问题(FAQ),方便读者查阅。 + +本指导在介绍过程中还包括一些“说明”。这些“说明”,表示例外情况或者额外信息的补充。“说明”在文中如下所示: + +> **说明:**
此处承载说明内容。 + diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/grid-breakpoint.md b/zh-cn/application-dev/key-features/multi-device-app-dev/grid-breakpoint.md deleted file mode 100644 index e669f13301d9c57a73bc25bb255ea0df820c6a39..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/grid-breakpoint.md +++ /dev/null @@ -1,82 +0,0 @@ -# 栅格断点系统 - - -栅格断点系统定义了不同水平宽度设备对应的Column数量关系,形成了一套断点规则定义。其以水平值作为断点依据,不同的设备根据自身当前水平宽度值在不同断点范围内的情况,显示不同数量的栅格数。 - - -![zh-cn_image_0000001292375365](figures/zh-cn_image_0000001292375365.png) - - -| 水平宽度 (vp) | SizeType类型 | Columns数量 | 默认Margin | 默认Gutter | 典型设备 | -| -------- | -------- | -------- | -------- | -------- | -------- | -| [0, 320) | XS | 2 | 12vp | 12vp | 智能穿戴 | -| [320, 600) | SM | 4 | 24vp | 24vp | 默认设备 | -| [600, 840) | MD | 8 | 32vp | 24vp | 智慧屏、竖屏状态的平板等 | -| [840, +∞) | LG | 12 | 48vp | 24vp | 车机、横屏状态的平板等 | - - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 请访问[栅格布局](../../ui/ui-ts-layout-grid-container.md),了解栅格布局更详细的介绍。 -> -> - 声明式开发范式,请访问[GridContainer组件](../../reference/arkui-ts/ts-container-gridcontainer.md)及[栅格设置](../../reference/arkui-ts/ts-universal-attributes-grid.md),了解栅格布局的详细用法。 -> -> - 类Web开发范式,通过[grid-container](../../reference/arkui-js/js-components-grid-container.md)、 [grid-row](../../reference/arkui-js/js-components-grid-row.md)、[grid-col](../../reference/arkui-js/js-components-grid-col.md)组件来实现栅格布局,请访问相应的链接了解其详细用法。 - - -## 示例 - -- 默认设备屏幕宽度为360vp,属于SizeType.SM类型设备,Column数量为4。根据示例代码配置,在该设备上,Left占1列,Center占2列,Right占1列。 - -- 平板屏幕宽度为1024vp,属于SizeType.LG类型设备,Column数量为12。根据示例代码配置,在该设备上,Left占2列,Center占7列,Right占3列。 - -![zh-cn_image_0000001245456434](figures/zh-cn_image_0000001245456434.jpg) - - -```ts -@Entry - @Component - struct GridContainerExample1 { - build(){ - GridContainer() { - Row({}) { - Row() { - Text('Left').fontSize(25) - } - .useSizeType({ - xs: { span:1, offset:0 }, sm: { span:1, offset:0 }, - md: { span:1, offset:0 }, lg: { span:2, offset:0 } - }) - .height("100%") - .backgroundColor(0x66bbb2cb) - Row() { - Text('Center').fontSize(25) - } - .useSizeType({ - xs: { span:1, offset:0 }, sm: { span:2, offset:1 }, - md: { span:5, offset:1 }, lg: { span:7, offset:2 } - }) - .height("100%") - .backgroundColor(0x66b6c5d1) - Row() { - Text('Right').fontSize(25) - } - .useSizeType({ - xs: { span:1, offset:0 }, sm: { span:1, offset:3 }, - md: { span:2, offset:6 }, lg: { span:3, offset:9 } - }) - .height("100%") - .backgroundColor(0x66bbb2cb) - } - .height(200) - } - .backgroundColor(0xf1f3f5) - .margin({ top:10 }) - } - } -``` - -## 相关实例 - -针对栅格断点系统开发,有以下相关实例可供参考: - -- [`Weather`:一多天气(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather) \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/ide-usage.md b/zh-cn/application-dev/key-features/multi-device-app-dev/ide-using.md similarity index 89% rename from zh-cn/application-dev/key-features/multi-device-app-dev/ide-usage.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/ide-using.md index 0f3caed8ffb52104477bf3f3d9a07bc7822895dd..eb71bb37ba08ab59e522f190d22690661eb0adc1 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/ide-usage.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/ide-using.md @@ -1,148 +1,150 @@ -# IDE使用 - - -DevEco Studio的基本使用,请参考[DevEco Studio使用指南](../../quick-start/deveco-studio-user-guide-for-openharmony.md)。本章主要介绍如何使用DevEco Studio进行多设备应用开发。 - - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> 本章的内容基于[DevEco Studio 3.0 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony)版本进行介绍,如您使用DevEco Studio其它版本,可能存在文档与产品功能界面、操作不一致的情况,请以实际功能界面为准。 - - -## 工程创建 - -参考[创建OpenHarmony工程](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-create-new-project-0000001263280423),先创建出最基本的项目工程。可以看到DevEco Studio创建出的默认工程,仅包含一个的entry类型的模块。 - -![zh-cn_image_0000001267274204](figures/zh-cn_image_0000001267274204.jpg) - -而在本文“[工程结构](introduction.md#部署模型)”小节中,推荐开发者采用common、features、product三层工程结构,这样在一个应用工程内可以更容易、清晰地管理多个设备的模块。工程结构示例如下所示: - - -``` -/application - ├── common # 公共特性目录 - │ - ├── features # 功能模块目录 - │ ├── feature1 # 子功能 - │ ├── feature2 # 子功能2 - │ └── ... # 子功能n - │ - └── product # 产品层目录 - ├── wearable # 智能穿戴泛类目录 - ├── default # 默认设备泛类目录 - └── ... -``` - -当然开发者也可以使用平级的目录进行模块管理,只是看上去会显得有点“杂乱”,工程结构示例如下所示: - - -``` -/application -├── common -├── feature1 -├── feature2 -├── featureN -├── wearable -├── default -└── productN -``` - - -## 新建Module - -参考[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434),新建三个npm模块,分别命名为common、feature1、feature2。参考[添加/删除Module](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-adding-deleting-module-0000001218760594),新建一个entry类型的模块,假设命名为“wearable”(仅仅为了说明某一类产品)。示例如下: - -![zh-cn_image_0000001315434285](figures/zh-cn_image_0000001315434285.png) - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 在一个工程中同一个设备类型只支持一个Entry类型的模块。 -> -> - 当前的DevEco Studio(3.0 Beta3版本)在创建工程时,设备类型仅能选择phone和tablet,默认该模块已经选择了entry类型,那么在创建wearable这个模块,只能选择feature类型。 -> -> - 在下一个小节,我们将介绍如何修改Module的配置,包括Module的类型以及其支持的设备类型等。 - - -## 修改Module配置 - - -### 修改Module名称 - -修改创建工程时默认的entry模块名称。在该模块上点击鼠标右键,依次选择”Refactor -> Rename”,将名称修改为default。 - -![zh-cn_image_0000001315914185](figures/zh-cn_image_0000001315914185.jpg) - - -### 修改Module类型及其设备类型 - -通过修改每个模块中的配置文件(module.json5)对模块进行配置,配置文件中各字段含义详见[配置文件说明](../../quick-start/stage-structure.md)。 - -- 将default模块的deviceTypes配置为["phone", "tablet"],同时将其type字段配置为entry。 - 即default模块编译出的hap包在默认设备和平板上安装和运行。 - - ![zh-cn_image_0000001267914116](figures/zh-cn_image_0000001267914116.png) - -- 将wearable模块的deviceTypes配置为["wearable"],同时将其type字段配置为entry。 - 即wearable模块编译出的hap包仅在智能穿戴设备上安装和运行。 - - ![zh-cn_image_0000001267514192](figures/zh-cn_image_0000001267514192.png) - - -## 调整目录结构 - -调整目录结构 - -在工程根目录(MyApplication)上点击鼠标右键,依次选择“New -> Directory”新建子目录。创建product和features两个子目录。 - -![zh-cn_image_0000001266874320](figures/zh-cn_image_0000001266874320.png) - -用鼠标左键将default目录拖拽到新建的product目录中,在IDE弹出的确认窗口中,点击“Refactor”即可。 - -![zh-cn_image_0000001315714137](figures/zh-cn_image_0000001315714137.jpg) - -按照同样的步骤,将wearable目录放到product目录中,将feature1和feature2放到features目录中。 - -![zh-cn_image_0000001316914105](figures/zh-cn_image_0000001316914105.png) - - -## 修改依赖关系 - -回顾之前小节中关于“工程结构”的介绍,我们推荐在common目录中存放基础公共代码,features目录中存放相对独立的功能模块代码,product目录中存放完全独立的产品代码。这样在product目录中依赖features和common中的公共代码来实现功能,可以最大程度实现代码复用。 - -配置依赖关系可以通过修改模块中的package.json文件。如下图所示,通过修改default模块中的package.json文件,使其可以使用common、feature1和feature2模块中的代码。更多详情参考[配置OpenHarmony npm包依赖](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386#section89674298391)。 - -![zh-cn_image_0000001267274208](figures/zh-cn_image_0000001267274208.png) - -同样的,修改feature1和feature2模块中的package.json文件,使其可以使用common模块中的代码。 - -修改package.json文件后,一定要点击右上角的“Sync Now”,否则改动不会生效! - - -## 引用npm包中的代码 - -在[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386)中,仅介绍了如何使用npm包中的页面和资源,本小节以例子的形式补充介绍如何使用npm包中的类和函数。 - -示例如下: - -- 在common模块中新增ComplexNumber类,用于表征复数(数学概念,由实部和虚部组成),该类包含toString()方法,将复数转换为字符形式。 - -- 在common模块中新增Add函数,用于计算并返回两个数字的和。 - -- 在default模块中,使用common模块新增的ComplexNumber类和Add函数。 - -1. 在”common/src/main/ets”目录中,按照需要新增文件和自定义类和函数。 - ![zh-cn_image_0000001315434289](figures/zh-cn_image_0000001315434289.png) - -2. 在”common/index.ets”文件中,申明需要export的类、函数的名称及在当前模块中的位置,否则其它模块无法使用。 - ![zh-cn_image_0000001315914189](figures/zh-cn_image_0000001315914189.png) - -3. 在default模块中import和使用这些类和函数。注意提前在default模块的package.json文件中配置对common模块的依赖关系。 - ![zh-cn_image_0000001267914120](figures/zh-cn_image_0000001267914120.png) - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> 如果需要将npm包发布供其他开发者使用,当前npm包可发布到npm官方中心仓和OpenHarmony npm专用仓,具体可参考[发布OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434#section663116411397)。 - - -## 总结 - -本章主要介绍了如何实现推荐的工程结构,以便更好的进行多设备应用开发。 - -关于IDE的基本使用,比如如何进行编译构建、如何签名、如何使用预览器等,[DevEco Studio使用指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-deveco-studio-overview-0000001263280421)中已经有非常详尽的介绍,本文不再重复介绍。 +# 工程管理 + + +DevEco Studio的基本使用,请参考[DevEco Studio使用指南](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/deveco-studio-user-guide-for-openharmony.md)。本章主要介绍如何使用DevEco Studio进行多设备应用开发。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 本章的内容基于[DevEco Studio 3.0 Beta3](https://developer.harmonyos.com/cn/develop/deveco-studio#download_beta_openharmony)版本进行介绍,如您使用DevEco Studio其它版本,可能存在文档与产品功能界面、操作不一致的情况,请以实际功能界面为准。 + + +## 工程创建 + +参考[创建OpenHarmony工程](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-create-new-project-0000001263280423),先创建出最基本的项目工程。可以看到DevEco Studio创建出的默认工程,仅包含一个的entry类型的模块。 + +![zh-cn_image_0000001267274204](figures/zh-cn_image_0000001267274204.jpg) + +如果直接使用如下所示的平级目录进行模块管理,工程逻辑结构较混乱且模块间的依赖关系不够清晰,不利于开发及后期维护。 + + +``` +/application +├── common +├── feature1 +├── feature2 +├── featureN +├── wearable +├── default +└── productN +``` + +更推荐使用本文[部署模型](introduction.md#部署模型)小节中介绍的common、features、product三层工程结构。工程结构示例如下所示: + + +``` +/application + ├── common # 公共特性目录 + │ + ├── features # 功能模块目录 + │ ├── feature1 # 子功能 + │ ├── feature2 # 子功能2 + │ └── ... # 子功能n + │ + └── product # 产品层目录 + ├── wearable # 智能穿戴泛类目录 + ├── default # 默认设备泛类目录 + └── ... +``` + +接下来将依次介绍如何新建Module、修改配置文件以及调整目录,以实现“一多”推荐的“三层工程结构”。 + + +## 新建Module + +参考[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434),新建三个npm模块,分别命名为common、feature1、feature2。参考[添加/删除Module](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-adding-deleting-module-0000001218760594),新建一个entry类型的模块,假设命名为“wearable”(仅仅为了说明某一类产品)。示例如下: + +![zh-cn_image_0000001315434285](figures/zh-cn_image_0000001315434285.png) + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 在一个工程中同一个设备类型只支持一个Entry类型的模块。 +> +> - 当前的DevEco Studio(3.0 Beta3版本)在创建工程时,设备类型仅能选择phone和tablet,默认该模块已经选择了entry类型,那么在创建wearable这个模块,只能选择feature类型。 +> +> - 在下一个小节,我们将介绍如何修改Module的配置,包括Module的类型以及其支持的设备类型等。 + + +## 修改Module配置 + + +### 修改Module名称 + +修改创建工程时默认的entry模块名称。在该模块上点击鼠标右键,依次选择”Refactor -> Rename”,将名称修改为default。 + +![zh-cn_image_0000001315914185](figures/zh-cn_image_0000001315914185.jpg) + + +### 修改Module类型及其设备类型 + +通过修改每个模块中的配置文件(module.json5)对模块进行配置,配置文件中各字段含义详见[配置文件说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/stage-structure.md)。 + +- 将default模块的deviceTypes配置为["phone", "tablet"],同时将其type字段配置为entry。 + 即default模块编译出的hap包在默认设备和平板上安装和运行。 + + ![zh-cn_image_0000001267914116](figures/zh-cn_image_0000001267914116.png) + +- 将wearable模块的deviceTypes配置为["wearable"],同时将其type字段配置为entry。 + 即wearable模块编译出的hap包仅在智能穿戴设备上安装和运行。 + + ![zh-cn_image_0000001267514192](figures/zh-cn_image_0000001267514192.png) + + +## 调整目录结构 + +调整目录结构 + +在工程根目录(MyApplication)上点击鼠标右键,依次选择“New -> Directory”新建子目录。创建product和features两个子目录。 + +![zh-cn_image_0000001266874320](figures/zh-cn_image_0000001266874320.png) + +用鼠标左键将default目录拖拽到新建的product目录中,在IDE弹出的确认窗口中,点击“Refactor”即可。 + +![zh-cn_image_0000001315714137](figures/zh-cn_image_0000001315714137.jpg) + +按照同样的步骤,将wearable目录放到product目录中,将feature1和feature2放到features目录中。 + +![zh-cn_image_0000001316914105](figures/zh-cn_image_0000001316914105.png) + + +## 修改依赖关系 + +回顾之前小节中关于“工程结构”的介绍,我们推荐在common目录中存放基础公共代码,features目录中存放相对独立的功能模块代码,product目录中存放完全独立的产品代码。这样在product目录中依赖features和common中的公共代码来实现功能,可以最大程度实现代码复用。 + +配置依赖关系可以通过修改模块中的package.json文件。如下图所示,通过修改default模块中的package.json文件,使其可以使用common、feature1和feature2模块中的代码。更多详情参考[配置OpenHarmony npm包依赖](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386#section89674298391)。 + +![zh-cn_image_0000001267274208](figures/zh-cn_image_0000001267274208.png) + +同样的,修改feature1和feature2模块中的package.json文件,使其可以使用common模块中的代码。 + +修改package.json文件后,一定要点击右上角的“Sync Now”,否则改动不会生效! + + +## 引用npm包中的代码 + +在[开发OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001252769386)中,仅介绍了如何使用npm包中的页面和资源,本小节以例子的形式补充介绍如何使用npm包中的类和函数。 + +示例如下: + +- 在common模块中新增ComplexNumber类,用于表征复数(数学概念,由实部和虚部组成),该类包含toString()方法,将复数转换为字符形式。 + +- 在common模块中新增Add函数,用于计算并返回两个数字的和。 + +- 在default模块中,使用common模块新增的ComplexNumber类和Add函数。 + +1. 在”common/src/main/ets”目录中,按照需要新增文件和自定义类和函数。 + ![zh-cn_image_0000001315434289](figures/zh-cn_image_0000001315434289.png) + +2. 在”common/index.ets”文件中,申明需要export的类、函数的名称及在当前模块中的位置,否则其它模块无法使用。 + ![zh-cn_image_0000001315914189](figures/zh-cn_image_0000001315914189.png) + +3. 在default模块中import和使用这些类和函数。注意提前在default模块的package.json文件中配置对common模块的依赖关系。 + ![zh-cn_image_0000001267914120](figures/zh-cn_image_0000001267914120.png) + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 如果需要将npm包发布供其他开发者使用,当前npm包可发布到npm官方中心仓和OpenHarmony npm专用仓,具体可参考[发布OpenHarmony npm包](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-development-npm-package-0000001222578434#section663116411397)。 + + +## 总结 + +本章主要介绍了如何实现推荐的工程结构,以便更好的进行多设备应用开发。 + +关于IDE的基本使用,比如如何进行编译构建、如何签名、如何使用预览器等,[DevEco Studio使用指南](https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ohos-deveco-studio-overview-0000001263280421)中已经有非常详尽的介绍,本文不再重复介绍。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-basics.md b/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-basics.md index ed59ac422c8e386e1aadbb1672f39e9197159d05..22fb79878de2f440362c029bbea26dfa58174baa 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-basics.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-basics.md @@ -1,23 +1,23 @@ -# 交互基础 - - -在全场景的数字体验中,越来越多类型的智能终端设备分布在用户的日常生活中,可交互的用户界面广泛存在于默认设备、平板、PC、智能穿戴设备、智慧屏、车机、虚拟现实(VR)和增强现实(AR)等设备上。应用可能在多种设备上运行或在单一设备上被用户通过多种输入方式操控,也可能在多种距离上被用户操控。这需要其用户界面能够识别和支持不同的交互场景,以便用户以习惯的、舒适的方法与其进行交互。 - - -![zh-cn_image_0000001224293580](figures/zh-cn_image_0000001224293580.png) - - -## 输入方式 - -典型的输入方式包括但不限于触屏上手指/手写笔等直接交互、鼠标/触摸板/键盘/表冠/遥控器/车机摇杆/旋钮/手柄/隔空手势等间接交互、以及语音交互。 - -设计和开发应用时,**设计师和开发者应考虑到应用具有使用多种输入方式的可能性**,并实现相应的功能,保证在当前输入方式下应用能够以正确的、符合用户习惯的方式进行响应。 - - -## 交互距离 - -典型的设备交互距离包括但不限于15cm(智能穿戴设备)、30cm(默认设备)、60cm(桌面设备)、260cm(大屏),具体距离会在用户使用过程中产生一定范围的变化。 - -设计和开发应用时,设计师和开发者应考虑到多种距离下使用的可能性,保证界面元素的大小、展示信息的密度符合用户的预期。 - -![zh-cn_image_0000001313720673](figures/zh-cn_image_0000001313720673.png) +# 交互基础 + + +在全场景的数字体验中,越来越多类型的智能终端设备分布在用户的日常生活中,可交互的用户界面广泛存在于默认设备、平板、PC、智能穿戴设备、智慧屏、车机、虚拟现实(VR)和增强现实(AR)等设备上。应用可能在多种设备上运行或在单一设备上被用户通过多种输入方式操控,也可能在多种距离上被用户操控。这需要其用户界面能够识别和支持不同的交互场景,以便用户以习惯的、舒适的方法与其进行交互。 + + +![zh-cn_image_0000001224293580](figures/zh-cn_image_0000001224293580.png) + + +## 输入方式 + +典型的输入方式包括但不限于触屏上手指/手写笔等直接交互、鼠标/触摸板/键盘/表冠/遥控器/车机摇杆/旋钮/手柄/隔空手势等间接交互、以及语音交互。 + +设计和开发应用时,**设计师和开发者应考虑到应用具有使用多种输入方式的可能性**,并实现相应的功能,保证在当前输入方式下应用能够以正确的、符合用户习惯的方式进行响应。 + + +## 交互距离 + +典型的设备交互距离包括但不限于15cm(智能穿戴设备)、30cm(默认设备)、60cm(桌面设备)、260cm(大屏),具体距离会在用户使用过程中产生一定范围的变化。 + +设计和开发应用时,设计师和开发者应考虑到多种距离下使用的可能性,保证界面元素的大小、展示信息的密度符合用户的预期。 + +![位图 21](figures/位图21.png) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-events-unification.md b/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-event-normalization.md similarity index 61% rename from zh-cn/application-dev/key-features/multi-device-app-dev/interaction-events-unification.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/interaction-event-normalization.md index 20e03164ee6e4865b3caac476d04e88a5a30fec3..193a6b740dfd6ad939168a14ef8101960211f29e 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-events-unification.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/interaction-event-normalization.md @@ -1,51 +1,51 @@ -# 交互归一 - - -对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,我们统一了各种交互方式的API,即实现了**交互归一**。 - - -## 基础输入 - -常见的基础输入方式及其在各输入设备上的表现如下图所示。 - -![zh-cn_image_0000001313602309](figures/zh-cn_image_0000001313602309.jpg) - -基础输入对应的开发接口,以及当前支持情况如下表所示。 - -| 输入 | 开发接口 | 触控屏 | 鼠标 | 触控板 | -| -------- | -------- | -------- | -------- | -------- | -| 点击 | [onClick](../../reference/arkui-ts/ts-universal-events-click.md) | √ | √ | √ | -| 长按 | [LongPressGesture](../../reference/arkui-ts/ts-basic-gestures-longpressgesture.md) | √ | √ | × | -| 双击 | [TapGesture](../../reference/arkui-ts/ts-basic-gestures-tapgesture.md) | √ | √ | √ | -| 轻扫 | [SwipeGesture](../../reference/arkui-ts/ts-basic-gestures-swipegesture.md) | √ | √ | √ | -| 滚动及平移 | [PanGesture](../../reference/arkui-ts/ts-basic-gestures-pangesture.md) | √ | √ | √ | -| 缩放 | [PinchGesture](../../reference/arkui-ts/ts-basic-gestures-pinchgesture.md) | √ | √ | √ | -| 旋转 | [RotationGesture](../../reference/arkui-ts/ts-basic-gestures-rotationgesture.md) | √ | NA | √ | - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 点击事件(onClick)其实是点击手势(TapGesture)的一个特殊场景(单指单次点击)。该场景使用的非常广泛,为了方便开发者使用及符合传统开发习惯,所以专门提供了开发接口。 -> -> - 触控板支持长按输入的功能正在开发中。 - - -## 拖拽事件 - -拖拽是应用开发中经常碰到的场景。拖拽发生在两个组件之间,它不是简单的单次输入,而是一个”过程”,通常包含如下步骤(以将组件A拖拽到组件B中为例)。 - -- 长按或点击组件A,触发拖拽。 - -- 保持按压或点击,持续将组件A向组件B拖拽。 - -- 抵达组件B中,释放按压点击,完成拖拽。 - -- 也可以在未抵达组件B的中途,释放按压点击,取消拖拽。 - -一个完整的拖拽事件,包含多个拖拽子事件,如下表所示(请访问拖拽事件了解详细用法)。当前触控屏和鼠标的拖拽事件已经实现”交互归一”,对触控屏的支持正在开发中。 - -| 名称 | 功能描述 | -| -------- | -------- | -| onDragStart | 绑定A组件,触控屏长按/鼠标左键按下后移动触发 | -| onDragEnter | 绑定B组件,触控屏手指、鼠标移动进入B组件瞬间触发 | -| onDragMove | 绑定B组件,触控屏手指、鼠标在B组件内移动触发 | -| onDragLeave | 绑定B组件,触控屏手指、鼠标移动退出B组件瞬间触发 | -| onDrop | 绑定B组件,在B组件内,触控屏手指抬起、鼠标左键松开时触发 | +# 交互归一 + + +对于不同类型的智能设备,用户可能有不同的交互方式,如通过触摸屏、鼠标、触控板等。如果针对不同的交互方式单独做适配,会增加开发工作量同时产生大量重复代码。为解决这一问题,我们统一了各种交互方式的API,即实现了**交互归一**。 + + +## 基础输入 + +常见的基础输入方式及其在各输入设备上的表现如下图所示。 + +![basic_guester](figures/basic_guester.jpg) + +基础输入对应的开发接口,以及当前支持情况如下表所示。 + + | 输入 | 开发接口 | 触控屏 | 鼠标 | 触控板 | +| -------- | -------- | -------- | -------- | -------- | +| 点击 | [onClick](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-events-click.md) | √ | √ | √ | +| 长按 | [LongPressGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-longpressgesture.md) | √ | √ | × | +| 双击 | [TapGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-tapgesture.md) | √ | √ | √ | +| 轻扫 | [SwipeGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-swipegesture.md) | √ | √ | √ | +| 滚动及平移 | [PanGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pangesture.md) | √ | √ | √ | +| 缩放 | [PinchGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-pinchgesture.md) | √ | √ | √ | +| 旋转 | [RotationGesture](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-gestures-rotationgesture.md) | √ | NA | √ | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 点击事件(onClick)其实是点击手势(TapGesture)的一个特殊场景(单指单次点击)。该场景使用的非常广泛,为了方便开发者使用及符合传统开发习惯,所以专门提供了开发接口。 +> +> - 触控板支持长按输入的功能正在开发中。 + + +## 拖拽事件 + +拖拽是应用开发中经常碰到的场景。拖拽发生在两个组件之间,它不是简单的单次输入,而是一个”过程”,通常包含如下步骤(以将组件A拖拽到组件B中为例)。 + +- 长按或点击组件A,触发拖拽。 + +- 保持按压或点击,持续将组件A向组件B拖拽。 + +- 抵达组件B中,释放按压点击,完成拖拽。 + +- 也可以在未抵达组件B的中途,释放按压点击,取消拖拽。 + +一个完整的拖拽事件,包含多个拖拽子事件,如下表所示(请访问拖拽事件了解详细用法)。当前触控屏和鼠标的拖拽事件已经实现”交互归一”,对触控屏的支持正在开发中。 + + | 名称 | 功能描述 | +| -------- | -------- | +| onDragStart | 绑定A组件,触控屏长按/鼠标左键按下后移动触发 | +| onDragEnter | 绑定B组件,触控屏手指、鼠标移动进入B组件瞬间触发 | +| onDragMove | 绑定B组件,触控屏手指、鼠标在B组件内移动触发 | +| onDragLeave | 绑定B组件,触控屏手指、鼠标移动退出B组件瞬间触发 | +| onDrop | 绑定B组件,在B组件内,触控屏手指抬起、鼠标左键松开时触发 | diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design-intro.md similarity index 80% rename from zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-intro.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design-intro.md index 45beccad0f3790fd37b87a3bf915ded3a5c308d6..3748dc26332ca137cf7516e9b141be075606efc5 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-intro.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design-intro.md @@ -1,7 +1,7 @@ -# 概述 - - -布局不是静态固定的,当显示环境发生变化时,如横竖屏切换、调节字体大小、应用分屏,要及时调整内容的布局方式以适应变化。本章提供了布局基础的概念和介绍。详见[布局基础](layout-grid.md)。 - - -了解布局的基础概念后,通过调用栅格系统、自适应布局和响应式布局能力就可以让内容更好地适配显示环境的变化。综合运用布局基础能力,可实现常用页面结构的多设备适配。详见[布局基础运用案例](layout-design-cases.md)。 +# 概述 + + +布局不是静态固定的,当显示环境发生变化时,如横竖屏切换、调节字体大小、应用分屏,要及时调整内容的布局方式以适应变化。本章提供了布局基础的概念和介绍。详见[布局基础](design-grid.md)。 + + +了解布局的基础概念后,通过调用栅格系统、自适应布局和响应式布局能力就可以让内容更好地适配显示环境的变化。综合运用布局基础能力,可实现常用页面结构的多设备适配。详见[布局基础运用案例](design-layout-cases.md)。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design.md b/zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design.md new file mode 100644 index 0000000000000000000000000000000000000000..4ecc2f241e1a9d0c64684a594081ac3c53b27499 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/interface-layout-design.md @@ -0,0 +1,9 @@ +# 界面布局 + + + +- **[概述](interface-layout-design-intro.md)** + +- **[布局基础](layout-design-basics.md)** + +- **[布局基础运用案例](design-layout-cases.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/introduction.md b/zh-cn/application-dev/key-features/multi-device-app-dev/introduction.md index d4710de462d7c3b7dbe576001b8fa76aeda3ffb8..cb987a900b203265a207a45a518a5a074d13674a 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/introduction.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/introduction.md @@ -1,150 +1,162 @@ -# 简介 - - -## 背景 - -随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。OpenHarmony 系统面向多终端提供了“一多”的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。 - -![zh-cn_image_0000001267340890](figures/zh-cn_image_0000001267340890.jpg) - - -## 定义及目标 - -**定义**:一套代码工程,一次开发上架,多端按需部署。 - -**目标**:支撑开发者快速高效开发多设备(“多种终端设备形态”的简称)应用,实现对不同设备兼容的同时提供跨设备的流转、迁移和协同的分布式体验。 - -![zh-cn_image_0000001315500981](figures/zh-cn_image_0000001315500981.jpg) - -为了实现“已整改”的目标,需要解决两个基础问题: - -- 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。 - -- 不同设备的系统能力有差异,如智能穿戴设备是否具备GPS、智慧屏是否具备摄像头等,功能如何兼容。 - -从第3章开始将从UX设计、系统能力等角度,详尽的解答上述问题。 - - -## 基础知识 - -为了更好的阅读后面的章节,本小节主要介绍了一些基础知识,方便读者理解内容。 - - -### 应用程序包结构 - -OpenHarmony 的应用以APP Pack (Application Package) 形式发布,它是由一个或多个HAP包以及描述每个HAP属性的pack.info文件组成。 - -HAP是OpenHarmony的安装包,一个HAP在工程目录中对应一个Module,由Module编译而来,可分为entry和feature两种类型的HAP。 - -- **entry**:应用的主模块包。一个APP中,对于同一设备类型,可以有一个或多个entry类型的HAP,来支持该设备类型中不同规格(如API版本、屏幕规格等)的具体设备。 - -- **feature**:应用的动态特性模块包。一个APP Pack可以包含零个、一个或多个feature类型的HAP。 - -![zh-cn_image_0000001266965046](figures/zh-cn_image_0000001266965046.png) - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - Module是开发者开发的相对独立的功能模块,由代码、资源、第三方库及应用配置文件组成,属于IDE开发视图的概念。Module分为entry、feature及har三种类型,相应的可以编译生成entry类型的HAP包、feature类型的HAP包,以及HAR包。 -> -> - 如果需要了解应用程序包结构更多详情,可以查看[包结构说明](../..//quick-start/package-structure.md)。 - - -### 方舟开发框架 - -OpenHarmony提供了方舟开发框架(简称:ArkUI),提供开发者进行应用UI开发时所必须的能力。 - -方舟开发框架提供了两种开发范式,分别是基于JS扩展的类Web开发范式(简称为“类Web开发范式”)和基于TS扩展的声明式开发范式(简称为“声明式开发范式”)。 - -- **类Web开发范式**:采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发。 - -- **声明式开发范式**:采用TS语言并进行声明式UI语法扩展,从组件、动效和状态管理三个维度提供了UI绘制能力。UI开发更接近自然语义的编程方式,让开发者直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。同时,选用有类型标注的TS语言,引入编译期的类型校验,更适用大型的应用开发。 - -两种开发范式的对比如下。 - - | **开发范式名称** | **语言生态** | **UI更新方式** | **适用场景** | **适用人群** | -| -------- | -------- | -------- | -------- | -------- | -| 类Web开发范式 | JS语言 | 数据驱动更新 | 界面较为简单的类小程序应用和卡片 | Web前端开发人员 | -| 声明式开发范式 | 扩展的TS语言(eTS) | 数据驱动更新 | 复杂度较大、团队合作度较高的程序 | 移动系统应用开发人员、系统应用开发人员 | - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 声明式开发范式占用内存更少,**更推荐开发者选用声明式开发范式来搭建应用UI界面**。 -> -> - 可以查看[方舟开发框架概述](../../ui/arkui-overview.md),了解方舟开发框架更多详情。 - - -### 部署模型 - -我们既可以在不同类型的设备上部署相同的HAP包,也可以在不同类型的设备上部署不同的HAP包。 - -“一多”有两种部署模型: - -- **部署模型A**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**相同**的HAP包(或HAP包组合)。 - -- **部署模型B**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**不同**的HAP包(或HAP包组合)。 - -建议开发者从设备类型及应用功能两个维度,结合具体的业务场景,考虑选择哪种部署模型。但不管采用哪种部署模型,都应该采用一次编译。 - -**设备类型** - - 从屏幕尺寸、交互方式及使用距离三个维度考虑,我们将常用的设备分为三大泛类: -- 默认设备、平板 - -- 车机、智慧屏 - -- 智能穿戴 - -对于相同泛类的设备,优先选择部署模型A,对于不同泛类设备,优先选择部署B。 - -**应用功能** - -- 方舟开发框架提供了丰富的多设备适配能力,相同泛类的设备通常总是可以使用部署模型。部署模型A需要的开发和维护工作量更小,而且可以保证不同类型设备上体验的一致性。 - -- 仅当同一泛类不同类型设备上规划的功能差异非常大时,才推荐使用部署模型B,如默认设备和平板分别交给两个团队设计、开发和维护等。 - -一般应用在不同设备上选择部署模型的思路如下: - -![zh-cn_image_0000001317848113](figures/zh-cn_image_0000001317848113.png) - -(备注:页面导航是用于应用内页面之间的跳转。例如默认设备设备上PageA跳转到PageB,Pad设备上也是PageA跳转到PageB,两种设备因为屏幕大小不同,默认设备上PageB是覆盖显示在PageA上的,Pad设备上PageB是在PageA的右边并且同时显示,但因为都是PageA跳转到PageB,那么我们认为它们的页面导航逻辑相同。) - -**工程结构** - -部署模型不同,往往代码工程结构也不同。 - -部署模型A对应的代码工程结构抽象后一般如下所示: - - -``` -/application -├── common # 可选。公共特性目录, har类型的module -├── features # 可选。功能模块目录 -│ ├── feature1 # 子功能1, har类型的module -│ ├── feature2 # 子功能2, har类型的module -│ └── ... -└── product # 必选。产品层目录, entry类型的module,编译后为hap包 -``` - -部署模型B对应的代码工程结构抽象后一般如下所示: - - -``` -/application -├── common # 可选。公共特性目录, har类型的module -├── features # 可选。功能模块目录 -│ ├── feature1 # 子功能1, har类型的module -│ ├── feature2 # 子功能2, har类型的module -│ └── ... -└── product # 必选。产品层目录 - ├── wearable # 智能穿戴泛类目录, entry类型的module,编译后为hap包 - ├── default # 默认设备泛类目录, entry类型的module,编译后为hap包 - └── ... -``` - -- common:公共特性目录,如工具类、公共配置等。 - -- features:功能模块目录,存放应用中相对独立的各个功能的实现(包括该功能相关的UI代码及业务逻辑代码),如账户管理等。 - -- product:产品层目录,通过引用common和feature目录中代码的方式做功能和特性的集成,同时也作为主入口。**这一层是两个部署模型主要差异点**,部署模型A可以直接在product目录中做功能和特性集成,部署模型B则需要在product目录下再建一级子目录,在不同的子目录中对不同的产品做差异化的功能和特性集成。 - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** - -> 无论是用部署模型A还是部署模型B,在开发阶段,都应考虑**不同类型设备间最大程度的复用代码**,以减少开发及后续维护的工作量。 +# 简介 + + +## 背景 + +随着终端设备形态日益多样化,分布式技术逐渐打破单一硬件边界,一个应用或服务,可以在不同的硬件设备之间随意调用、互助共享,让用户享受无缝的全场景体验。而作为应用开发者,广泛的设备类型也能为应用带来广大的潜在用户群体。但是如果一个应用需要在多个设备上提供同样的内容,则需要适配不同的屏幕尺寸和硬件,开发成本较高。OpenHarmony 系统面向多终端提供了“一次开发,多端部署”(后文中简称为“一多”)的能力,让开发者可以基于一种设计,高效构建多端可运行的应用。 + +![zh-cn_image_0000001267340890](figures/zh-cn_image_0000001267340890.jpg) + + +## 定义及目标 + +**定义**:一套代码工程,一次开发上架,多端按需部署。 + +**目标**:支撑开发者快速高效的开发支持多种终端设备形态的应用,实现对不同设备兼容的同时,提供跨设备的流转、迁移和协同的分布式体验。 + +![multi_device](figures/multi_device.jpg) + +为了实现“一多”的目标,需要解决两个基础问题: + +- 不同设备间的屏幕尺寸、色彩风格等存在差异,页面如何适配。 + +- 不同设备的系统能力有差异,如智能穿戴设备是否具备定位能力、智慧屏是否具备摄像头等,功能如何兼容。 + +从第4章开始将从UX设计、系统能力等角度,详尽的解答上述问题。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 应用开发不仅包含应用页面开发,还包括应用后端功能开发以及服务器端开发等。 +> +> - 本文旨在指导开发者如何在OpenHarmony系统中开发“一多”应用,服务器端开发不在本文探讨范围内。 + + +## 基础知识 + +为了更好的阅读后面的章节,本小节主要介绍了一些基础知识,方便读者理解内容。 + + +### 应用程序包结构 + +OpenHarmony 的应用以APP Pack (Application Package) 形式发布,它是由一个或多个HAP包以及描述每个HAP包属性的pack.info文件组成。 + +HAP包是OpenHarmony的安装包,一个HAP在工程目录中对应一个Module,由Module编译而来,可分为entry和feature两种类型的HAP。 + +- **entry**:应用的主模块包。一个APP中,对于同一设备类型,可以有一个或多个entry类型的HAP,来支持该设备类型中不同规格(如API版本、屏幕规格等)的具体设备。 + +- **feature**:应用的动态特性模块包。一个APP Pack可以包含零个、一个或多个feature类型的HAP。 + +![zh-cn_image_0000001266965046](figures/zh-cn_image_0000001266965046.png) + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - Module是开发者开发的相对独立的功能模块,由代码、资源、第三方库及应用配置文件组成,属于IDE开发视图的概念。Module分为entry、feature及har三种类型,相应的可以编译生成entry类型的HAP包、feature类型的HAP包,以及har包。 +> +> - 如果需要了解应用程序包结构更多详情,可以查看[包结构说明](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/quick-start/package-structure.md)。 + + +### 方舟开发框架 + +OpenHarmony提供了方舟开发框架(简称:ArkUI),提供开发者进行应用UI开发时所必须的能力。 + +方舟开发框架提供了两种开发范式,分别是基于JS扩展的类Web开发范式(后文中简称为“类Web开发范式”)和基于TS扩展的声明式开发范式(后文中简称为“声明式开发范式”)。 + +- **类Web开发范式**:采用经典的HML、CSS、JavaScript三段式开发方式。使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发更新。此种开发方式,更接近Web前端开发者的使用习惯,快速将已有的Web应用改造成方舟开发框架应用。主要适用于界面较为简单的中小型应用开发。 + +- **声明式开发范式**:采用TS语言并进行声明式UI语法扩展,从组件、动效和状态管理三个维度提供了UI绘制能力。UI开发更接近自然语义的编程方式,让开发者直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。同时,选用有类型标注的TS语言,引入编译期的类型校验,更适用大型的应用开发。 + +两种开发范式的对比如下。 + + | **开发范式名称** | **语言生态** | **UI更新方式** | **适用场景** | **适用人群** | +| -------- | -------- | -------- | -------- | -------- | +| 类Web开发范式 | JS语言 | 数据驱动更新 | 界面较为简单的类小程序应用和卡片 | Web前端开发人员 | +| 声明式开发范式 | 扩展的TS语言(eTS) | 数据驱动更新 | 复杂度较大、团队合作度较高的程序 | 移动系统应用开发人员、系统应用开发人员 | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 声明式开发范式占用内存更少,**更推荐开发者选用声明式开发范式来搭建应用UI界面**。 +> +> - 可以查看[方舟开发框架概述](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/arkui-overview.md),了解方舟开发框架更多详情。 + + +### 部署模型 + +“一多”有两种部署模型: + +- **部署模型A**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**相同**的HAP包(或HAP包组合)。 + +- **部署模型B**:不同类型的设备上按照一定的工程结构组织方式,通过一次编译生成**不同**的HAP包(或HAP包组合)。 + +建议开发者从设备类型及应用功能两个维度,结合具体的业务场景,考虑选择哪种部署模型。但不管采用哪种部署模型,都应该采用一次编译。 + +**设备类型** + + 从屏幕尺寸、交互方式及使用距离三个维度考虑,我们将常用的设备分为三大泛类: +- 默认设备、平板 + +- 车机、智慧屏 + +- 智能穿戴 + +对于相同泛类的设备,优先选择部署模型A,对于不同泛类设备,优先选择部署模型B。 + +**应用功能** + +- 方舟开发框架提供了丰富的多设备适配能力,相同泛类的设备通常总是可以使用部署模型A。部署模型A需要的开发和维护工作量更小,而且可以保证不同类型设备上体验的一致性。 + +- 仅当同一泛类不同类型设备上规划的功能差异非常大时,才推荐使用部署模型B,如默认设备和平板分别交给两个团队设计、开发和维护等。 + +一般应用在不同设备上选择部署模型的思路如下: + +![zh-cn_image_0000001400300617](figures/zh-cn_image_0000001400300617.png) + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 页面导航逻辑是指应用内页面之间的跳转关系。假设默认设备上页面A跳转到页面B,平板设备上也是页面A跳转到页面B。因为两种设备屏幕大小不同,默认设备上页面B是覆盖显示在页面A上的,平板设备上页面B是在页面A的右边并且同时显示,但因为都是页面A跳转到页面B,那么我们认为它们的页面导航逻辑相同。 + +**工程结构** + +“一多”推荐在应用开发过程中使用如下的“三层工程结构”。 + +- common:公共特性目录,如工具类、公共配置等。 + +- features:功能模块目录,存放应用中相对独立的各个功能的实现(包括该功能相关的UI代码及业务逻辑代码),如帐户管理等。 + +- product:产品层目录,通过引用common和feature目录中代码的方式做功能和特性的集成,同时也作为主入口。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> features层可横向调用和依赖common层能力;product层不可横向调用,可依赖features层和common层,且不能有反向依赖。 + +部署模型不同,相应的代码工程结构也有差异。部署模型A和部署模型B的主要差异点集中在product层: + +- 部署模型A可以直接在product目录中做功能和特性集成。 + +- 部署模型B需要在product目录下再建一级子目录,在不同的子目录中对不同的产品做差异化的功能和特性集成。 + +部署模型A对应的代码工程结构抽象后一般如下所示: + + +``` +/application +├── common # 可选。公共特性目录, har类型的module +├── features # 可选。功能模块目录 +│ ├── feature1 # 子功能1, har类型的module +│ ├── feature2 # 子功能2, har类型的module +│ └── ... +└── product # 必选。产品层目录, entry类型的module,编译后为hap包 +``` + +部署模型B对应的代码工程结构抽象后一般如下所示: + + +``` +/application +├── common # 可选。公共特性目录, har类型的module +├── features # 可选。功能模块目录 +│ ├── feature1 # 子功能1, har类型的module +│ ├── feature2 # 子功能2, har类型的module +│ └── ... +└── product # 必选。产品层目录 + ├── wearable # 智能穿戴泛类目录, entry类型的module,编译后为hap包 + ├── default # 默认设备泛类目录, entry类型的module,编译后为hap包 + └── ... +``` + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 无论是用部署模型A还是部署模型B,在开发阶段,都应考虑**不同类型设备间最大程度的复用代码**,以减少开发及后续维护的工作量。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-basics.md b/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-basics.md new file mode 100644 index 0000000000000000000000000000000000000000..65b9b0edf0358801d59e6e81caae8de1b327d3ae --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/layout-design-basics.md @@ -0,0 +1,9 @@ +# 布局基础 + + + +- **[栅格系统](design-grid.md)** + +- **[自适应布局](design-adaptive-layout.md)** + +- **[响应式布局](design-responsive-layout.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/layout-intro.md index a340691d63fdec7bcb261044c386dc3e02afb1f9..2dca7e747f0e42ae0ad8c0c62df9a08ac216b3eb 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/layout-intro.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/layout-intro.md @@ -1,18 +1,30 @@ -# 布局能力简介 +# 布局简介 -开发多设备上同一页面时,建议开发者优先使用一套布局,尽可能的实现代码复用。 +布局可以分为自适应布局和响应式布局,二者的介绍如下表所示。 -一般情况下,可以通过页面的组件结构(组件个数、组件的父子/兄弟关系、组件类型)来判断是否可以使用一套布局: +| 名称 | 简介 | +| -------- | -------- | +| 自适应布局 | 当外部容器大小发生变化时,元素可以**根据相对关系自动变化**以适应外部容器变化的布局能力。相对关系如占比、固定宽高比、显示优先级等。当前自适应布局能力有7种:[拉伸能力](adaptive-layout.md#拉伸能力)、[均分能力](adaptive-layout.md#均分能力)、[占比能力](adaptive-layout.md#占比能力)、[缩放能力](adaptive-layout.md#缩放能力)、[延伸能力](adaptive-layout.md#延伸能力)、[隐藏能力](adaptive-layout.md#隐藏能力)、[折行能力](adaptive-layout.md#折行能力)。自适应布局能力可以实现界面显示随外部容器大小连续变化。 | +| 响应式布局 | 当外部容器大小发生变化时,元素可以**根据断点、栅格或特定的特征(如屏幕方向、窗口宽高等)自动变化**以适应外部容器变化的布局能力。当前响应式布局能力有3种:[断点](responsive-layout.md#断点)、[媒体查询](responsive-layout.md#媒体查询)、[栅格布局](responsive-layout.md#栅格布局)。响应式布局可以实现界面随外部容器大小有级不连续变化,通常不同特征下的界面显示会有较大的差异。 | -- 对于页面组件结构相同的场景,在开发过程中可以灵活使用[自适应布局](adaptive-layout-intro.md)和[栅格布局](grid-breakpoint.md)能力来达到预期效果。 +自适应布局和响应式布局常常需要借助容器类组件实现,或与容器类组件搭配使用。 -- 对于页面组件结构不同的场景,可以借助[媒体查询](media-query.md)能力动态加载多套布局。 +- 自适应布局常常需要借助[Row组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-row.md)、[Column组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-column.md)或[Flex组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-flex.md)实现。 + + ![image-20220922185907892](figures/image-20220922185907892.png) + +- 响应式布局常常与[GridRow组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md)、[Grid组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)、[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)、[Swiper组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)或[Tabs组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)搭配使用。 + + ![image-20220922190217247](figures/image-20220922190217247.png) + + + +接下来将依次介绍自适应布局和响应式布局,同时结合实际,通过典型布局场景以及典型页面场景详细介绍两种布局能力的用法。 -下面将详细介绍这些布局能力。 ## 相关实例 针对一次开发,多端部署,有以下相关实例可供参考: @@ -22,3 +34,4 @@ - [`AdaptiveCapabilities`:多设备自适应能力(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/AdaptiveCapabilities) - [`JsAdaptiveCapabilities`:多设备自适应能力(JS)(API8)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/JsAdaptiveCapabilities) - [一次开发多端部署(eTS)(API8)](https://gitee.com/openharmony/codelabs/tree/master/ETSUI/MultiDeploymentEts) + diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/layout.md b/zh-cn/application-dev/key-features/multi-device-app-dev/layout.md new file mode 100644 index 0000000000000000000000000000000000000000..b7153656b169dd9ef85285165109d03338077267 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/layout.md @@ -0,0 +1,13 @@ +# 布局能力 + + + +- **[布局简介](layout-intro.md)** + +- **[自适应布局](adaptive-layout.md)** + +- **[响应式布局](responsive-layout.md)** + +- **[典型布局场景](typical-layout-scenario.md)** + +- **[典型页面场景](typical-page-layout.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/man-machine-interaction.md b/zh-cn/application-dev/key-features/multi-device-app-dev/man-machine-interaction.md new file mode 100644 index 0000000000000000000000000000000000000000..2aab672e810432bd69013ea350724fe5fac5dd73 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/man-machine-interaction.md @@ -0,0 +1,9 @@ +# 人机交互 + + + +- **[交互基础](interaction-basics.md)** + +- **[常见输入方式](common-input-modes.md)** + +- **[交互事件归一](design-interaction-event-normalization.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/media-query.md b/zh-cn/application-dev/key-features/multi-device-app-dev/media-query.md deleted file mode 100644 index 2e38c798351bd22335dae4ad172b6ad138c7e29b..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/media-query.md +++ /dev/null @@ -1,92 +0,0 @@ -# 媒体查询 - - -媒体查询是一种常用的功能,在移动设备上应用非常广泛。开发者经常需要根据设备的大致类型或特定的特征和设备参数(例如屏幕分辨率)来修改应用的样式。为此媒体查询提供了如下功能: - - -- 针对设备和应用的属性信息,可以设计出相匹配的布局样式。 - -- 当屏幕发生动态改变时(比如横竖屏切换、屏幕宽高比),页面布局同步更新。 - - -当前支持对如下媒体特征做媒体查询。 - - -| 类型 | 说明 | -| -------- | -------- | -| height | 应用页面显示区域的高度。 | -| min-height | 应用页面显示区域的最小高度。 | -| max-height | 应用页面显示区域的最大高度。 | -| width | 应用页面显示区域的宽度。 | -| min-width | 应用页面显示区域的最小宽度。 | -| max-width | 应用页面显示区域的最大宽度。 | -| resolution | 设备的分辨率,支持dpi,dppx和dpcm单位。 | -| min-resolution | 设备的最小分辨率。 | -| max-resolution | 设备的最大分辨率。 | -| orientation | 屏幕的方向,支持portrait(竖屏)和landscape(横屏)。 | -| device-type | 设备类型,支持tablet、tv、wearable等。 | - - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 声明式开发范式,请查看[媒体查询](../../ui/ui-ts-layout-mediaquery.md)了解详细用法。 -> -> - 类Web开发范式,支持在js文件和css文件中使用媒体查询,请查看[js媒体查询](../../reference/apis/js-apis-mediaquery.md)和[css媒体查询](../../reference/arkui-js/js-components-common-mediaquery.md)了解详细用法。 -> -> - 媒体查询能力最为强大,它可以改变页面组件结构,而自适应布局和栅格布局均无此能力。 -> -> - 相对于其它”一多”能力,媒体查询可能增加较多代码量。在可以满足需求的前提下,建议优先使用其它”一多”能力。 - - -## 示例: - -如下图,媒体查询不仅可以改变页面中的元素属性(文字内容、文字颜色),还可以改变页面结构(是否显示图片)。 - - -![zh-cn_image_0000001226091264](figures/zh-cn_image_0000001226091264.jpg) - - - -```ts -import mediaquery from '@ohos.mediaquery' - -@Entry -@Component -struct MediaQuerySample { - @State color: string = '#DB7093'; - @State text: string = 'Portrait'; - @State flag: boolean = false; - private listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(orientation: landscape)'); - - onOrientationChange = (mediaQueryResult) => { - if (mediaQueryResult.matches) { - this.color = '#FFD700'; - this.text = 'Landscape'; - this.flag = true; - } else { - this.color = '#DB7093'; - this.text = 'Portrait'; - this.flag = false; - } - } - - private aboutToAppear(): void { - this.listener.on('change', this.onOrientationChange); - } - - private aboutToDisappear(): void { - this.listener.off('change', this.onOrientationChange); - } - - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - if (this.flag) { // 通过媒体查询,改变布局 - Image($r("app.media.my_image")) - .width(100) - .height(100) - } - Text(this.text).fontSize(24).fontColor(this.color) - } - .width('100%').height('100%') - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/music-album-page.md b/zh-cn/application-dev/key-features/multi-device-app-dev/music-album-page.md new file mode 100644 index 0000000000000000000000000000000000000000..dbf0140ee2be9f4006826160382c50ed12dbe8b4 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/music-album-page.md @@ -0,0 +1,244 @@ +# 音乐专辑页 + + +本小节将以音乐专辑页为例,介绍如何使用自适应布局能力和响应式布局能力适配不同尺寸窗口。本示例已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/MusicAlbum)中开源,读者可以根据需要自行下载源码并运行及查看效果。 + + +## 页面设计 + +音乐专辑页的页面设计如下。 + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001381013985](figures/zh-cn_image_0000001381013985.png) | ![zh-cn_image_0000001381133197](figures/zh-cn_image_0000001381133197.png) | ![zh-cn_image_0000001329813432](figures/zh-cn_image_0000001329813432.png) | + +同样观察音乐专辑的页面设计,不同断点下的页面设计有较多相似的地方。 + +据此,我们可以将页面分拆为多个组成部分。 + +1. 标题栏 + +2. 歌单封面 + +3. 歌单列表 + +4. 播放控制栏 + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001380933349](figures/zh-cn_image_0000001380933349.jpg) | ![zh-cn_image_0000001330133330](figures/zh-cn_image_0000001330133330.jpg) | ![zh-cn_image_0000001381013989](figures/zh-cn_image_0000001381013989.jpg) | + + +## 标题栏 + +不同断点下,标题栏始终只显示“返回按钮”、“歌单”以及“更多按钮”,但“歌单”与“更多按钮”之间的间距不同。由于不同断点下标题栏的背景色也有较大差异,因此无法使用拉伸能力实现,此场景更适合使用栅格实现。我们可以将标题栏划分为“返回按钮及歌单”和“更多按钮”两部分,这两部分在不同断点下占据的列数如下图所示。另外,还可以借助OnBreakpointChange事件,调整不同断点下这两部分的背景色。 + + | | sm | md | lg | +| -------- | -------- | -------- | -------- | +| 效果图 | ![zh-cn_image_0000001329817776](figures/zh-cn_image_0000001329817776.png) | ![zh-cn_image_0000001381018337](figures/zh-cn_image_0000001381018337.png) | ![zh-cn_image_0000001381137517](figures/zh-cn_image_0000001381137517.jpg) | +| 栅格布局图 | ![zh-cn_image_0000001330137692](figures/zh-cn_image_0000001330137692.png) | ![zh-cn_image_0000001329977740](figures/zh-cn_image_0000001329977740.png) | ![zh-cn_image_0000001329658136](figures/zh-cn_image_0000001329658136.png) | + + +``` +@Component +export struct PlayListHeader { + @State moreBackgroundColor: Resource = $r('app.color.play_list_cover_background_color'); + build() { + GridRow() { + GridCol({span: {sm:6, md: 6, lg:4}}) { + Row() { + Image($r('app.media.ic_back')).height('24vp').width('24vp') + } + .width('100%') + .height('50vp') + .justifyContent(FlexAlign.Start) + .alignItems(VerticalAlign.Center) + .padding({left:$r('app.float.default_margin')}) + .backgroundColor($r('app.color.play_list_cover_background_color')) + } + GridCol({span: {sm:6, md: 6, lg:8}}) { + Row() { + Image($r('app.media.ic_add')).height('24vp').width('24vp') + } + .width('100%') + .height('50vp') + .justifyContent(FlexAlign.End) + .alignItems(VerticalAlign.Center) + .padding({right:$r('app.float.default_margin')}) + .backgroundColor(this.moreBackgroundColor) + } + }.onBreakpointChange((currentBreakpoint) => { + // 调整不同断点下返回按钮及歌单的背景色 + if (currentBreakpoint === 'sm') { + this.moreBackgroundColor = $r('app.color.play_list_cover_background_color'); + } else { + this.moreBackgroundColor = $r('app.color.play_list_songs_background_color'); + } + }).height('100%').width('100%') + } +} +``` + + +## 歌单封面 + +歌单封面由封面图片、歌单介绍及常用操作三部分组成,这三部分的布局在md和lg断点下完全相同,但在sm断点下有较大差异。此场景同样可以用栅格实现。 + + | | sm | md/lg | +| -------- | -------- | -------- | +| 效果图 | ![zh-cn_image_0000001329660244](figures/zh-cn_image_0000001329660244.jpg) | ![zh-cn_image_0000001381379829](figures/zh-cn_image_0000001381379829.png) | +| 栅格布局图 | ![zh-cn_image_0000001381220165](figures/zh-cn_image_0000001381220165.png) | ![zh-cn_image_0000001381220169](figures/zh-cn_image_0000001381220169.png) | + + +``` +@Component +export default struct PlayListCover { + ... + build() { + Column() { + // 借助栅格组件实现总体布局 + GridRow() { + // 歌单图片 + GridCol({ span: { sm: 4, md: 10 }, offset: { sm: 0, md: 1, lg: 1 } }) { + this.CoverImage() + } + // 歌单介绍 + GridCol({ span: { sm: 8, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) { + this.CoverIntroduction() + } + // 歌单操作 + GridCol({ span: { sm: 12, md: 10 }, offset: { sm: 0, md: 2, lg: 2 } }) { + this.CoverOptions() + }.margin({ + top: this.currentBreakpoint === 'sm' ? 15 : 0, + bottom: this.currentBreakpoint === 'sm' ? 15 : 0 + }) + } + .margin({ left: this.coverMargin, right: this.coverMargin }) + } + .height(this.currentBreakpoint === 'sm' ? this.coverHeight : '100%') + .padding({ top: this.currentBreakpoint === 'sm' ? 50 : 70 }) + } +} +``` + + +## 歌单列表 + +不同断点下,歌单列表的样式基本一致,但sm和md断点下是歌单列表是单列显示,lg断点下是双列显示。可以通过[List组件](https://gitee.com/fanzhaonan/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)的lanes属性实现这一效果。 + + +``` +@Component +export default struct PlayList { + ... + build() { + Column() { + this.PlayAll() + Scroll() { + List() { + LazyForEach(new MyDataSource(songList), item => { + ListItem() { + this.SongItem(item.title, item.label, item.singer) + } + }, item => item.id) + } + .width('100%') + .height('100%') + // 配置不同断点下歌单列表的列数 + .lanes(this.currentBreakpoint === 'lg' ? 2 : 1) + } + .backgroundColor('#fff') + .margin({ top: 50, bottom: this.currentBreakpoint === 'sm' ? this.coverHeight : 0 }) + } + .padding({top: 50,bottom: 48}) + } +} +``` + + +## 播放控制栏 + +在不同断点下,播放控制栏显示的内容完全一致,唯一的区别是歌曲信息与播放控制按钮之间的间距有差异,这是典型的拉伸能力的使用场景。 + + +``` +@Component +export struct MusicBar { + build() { + Row() { + Image($r('app.media.pic_album')).height(32).width(32).margin({right: 12}) + SongTitle() + // 通过Blank组件实现拉伸能力 + Blank() + Image($r('app.media.icon_play')).height(26).width(26).margin({right: 16}) + Image($r('app.media.ic_next')).height(24).width(24).margin({right: 16}) + Image($r('app.media.ic_Music_list')).height(24).width(24) + } + .width('100%') + .height(48) + .backgroundColor('#D8D8D8') + .alignItems(VerticalAlign.Center) + .padding({left: 16, right: 16}) + } +} +``` + + +## 运行效果 + +将页面中的四部分组合在一起,即可显示完整的页面。 + +其中歌单封面和歌单列表这两部分的相对位置,在sm断点下是上下排布,在md和lg断点下是左右排布,也可以用栅格来实现目标效果。 + + | | sm | md | lg | +| -------- | -------- | -------- | -------- | +| 效果图 | ![zh-cn_image_0000001381026609](figures/zh-cn_image_0000001381026609.jpg) | ![zh-cn_image_0000001381145789](figures/zh-cn_image_0000001381145789.jpg) | ![zh-cn_image_0000001329666380](figures/zh-cn_image_0000001329666380.jpg) | +| 栅格布局图 | ![zh-cn_image_0000001330145976](figures/zh-cn_image_0000001330145976.png) | ![zh-cn_image_0000001381385985](figures/zh-cn_image_0000001381385985.png) | ![zh-cn_image_0000001381226321](figures/zh-cn_image_0000001381226321.png) | + + +``` +@Component +export default struct MusicContent { + ... + build() { + GridRow() { + // 歌单封面 + GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 4 } }) { + PlayListCover() + } + // 歌单列表 + GridCol({ span: { xs: 12, sm: 12, md: 6, lg: 8 } }) { + PlayList() + } + } + .height('100%') + } +} +``` + +最后将页面各部分组合在一起即可。 + + +``` +@Entry +@Component +struct Index { + build() { + Column() { + // 标题栏 + PlayListHeader() + // 歌单 + MusicContent() + // 播放控制栏 + MusicBar() + }.width('100%').height('100%') + } +} +``` + +音乐专辑页面的运行效果如下所示。 + + | sm | md | lg | +| -------- | -------- | -------- | +| ![MusicAlbum_sm_running](figures/MusicAlbum_sm_running.png) | ![MusicAlbum_md_running](figures/MusicAlbum_md_running.png) | ![MusicAlbum_lg_running](figures/MusicAlbum_lg_running.png) | diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/navigation-design.md b/zh-cn/application-dev/key-features/multi-device-app-dev/navigation-design.md index eaefbf16b24050847f960e11c2d8577fe7f4afdb..7bec736913b899523468cad314227f917c734231 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/navigation-design.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/navigation-design.md @@ -1,70 +1,70 @@ -# 应用导航结构设计要求 - - -应用中的导航用于引导用户在应用的各个页面进行浏览。好的导航让用户知道身处何处,去往何方,以及来自哪里。 - - -## 导航的原则 - -导航需要遵循以下原则: - -- **一致**:导航操作的结果应该与用户的期望保持一致。相同或类似的场景使用用户熟悉的界面布局和控件,在多设备上确保一致的应用架构和导航行为,让用户无论在什么页面,都知道如何导航。例如二级界面使用左上角的返回按钮来返回界面的上一个层级。 - -- **清晰**:导航应该提供清晰的路径。用户使用的时候,逻辑关系简单且容易理解,能够知道当前处在界面的什么位置,操作后将会跳转到什么位置,不会迷失方向。例如使用底部页签,让用户在平级页面之间进行切换。 - -导航要避免以下设计: - -- **层级过深**:导航层级建议在三层以内。对于太深的层次,会带来操作效率的问题。如果确实需要深层级设计,建议使用面包屑设计或增加一键回到首页的功能。 - -- **导航复杂**:在侧边导航中,使用底部页签,会让操作变得复杂,建议仅使用侧边导航。 - - -## 导航的分类 - -常用的应用导航有:平级导航、层级导航和混合导航。 - -**平级导航** - -平级导航结构中,页面均处在同一层级。 - -使用场景:用于展示同等地位或同等层级的界面。 - -![zh-cn_image_0000001224053150](figures/zh-cn_image_0000001224053150.jpg) - -例如:以Tab方式组成的页面。图中照片、相册、发现为一级界面,从视频相册进入二级内容界面。 - -![zh-cn_image_0000001226444718](figures/zh-cn_image_0000001226444718.png) - -多设备设计:可转化导航类控件到符合设备体验的位置上。默认设备上使用Tab导航,PAD和PC使用侧边Tab导航,智慧屏使用顶部Tab导航。 - -![zh-cn_image_0000001270924709](figures/zh-cn_image_0000001270924709.png) - -**层级导航** - -层级导航结构由父页面和子页面组成。父页面可以有一个或多个子页面。每个子页面都有一个父页面。 - -层级导航适用于多层级的复杂结构。层级结构深的内容,用户访问的路径变长,效率降低,可以通过适当的层级穿透设计(例如:控制中心中的蓝牙开关,解决了进“设置-蓝牙”界面设置操作路径过长的问题)解决此问题。 - -使用场景:页面存在上下级关系的应用。 - -![zh-cn_image_0000001224173138](figures/zh-cn_image_0000001224173138.jpg) - -例如:通过从内容进入后经返回键返回之前的页面。 - -![zh-cn_image_0000001270804909](figures/zh-cn_image_0000001270804909.png) - -多设备设计:可以考虑将上下层级的界面在同一界面展示。默认设备和智慧屏上使用上下层级关系。平板和PC使用上分栏的方式展示内容。 - -![zh-cn_image_0000001226124842](figures/zh-cn_image_0000001226124842.png) - -**混合导航** - -在实际应用设计中,仅使用平级或层级导航可能无法应对更复杂的业务结构。此时需区分不同页面的导航关系,对同等地位或同等层级的页面使用平级导航结构,对具有复杂关系的页面使用层级导航结构。 - -使用场景:应用由几个同等级的模块组成,每个模块又有上下层级关系页面。 - -![zh-cn_image_0000001268653317](figures/zh-cn_image_0000001268653317.jpg) - -多设备设计:可以根据平级导航、层级导航自身的设计规则综合运用,一般平级导航优先级比层级高。 - -![zh-cn_image_0000001263489242](figures/zh-cn_image_0000001263489242.png) +# 应用导航结构设计要求 + + +应用中的导航用于引导用户在应用的各个页面进行浏览。好的导航让用户知道身处何处,去往何方,以及来自哪里。 + + +## 导航的原则 + +导航需要遵循以下原则: + +- **一致:**导航操作的结果应该与用户的期望保持一致。相同或类似的场景使用用户熟悉的界面布局和控件,在多设备上确保一致的应用架构和导航行为,让用户无论在什么页面,都知道如何导航。例如二级界面使用左上角的返回按钮来返回界面的上一个层级。 + +- **清晰:**导航应该提供清晰的路径。用户使用的时候,逻辑关系简单且容易理解,能够知道当前处在界面的什么位置,操作后将会跳转到什么位置,不会迷失方向。例如使用底部页签,让用户在平级页面之间进行切换。 + +导航要避免以下设计: + +- **层级过深:**导航层级建议在三层以内。对于太深的层次,会带来操作效率的问题。如果确实需要深层级设计,建议使用面包屑设计或增加一键回到首页的功能。 + +- **导航复杂:**在侧边导航中,使用底部页签,会让操作变得复杂,建议仅使用侧边导航。 + + +## 导航的分类 + +常用的应用导航有:平级导航、层级导航和混合导航。 + +**平级导航** + +平级导航结构中,页面均处在同一层级。 + +使用场景:用于展示同等地位或同等层级的界面。 + +![zh-cn_image_0000001224053150](figures/zh-cn_image_0000001224053150.jpg) + +例如:以Tab方式组成的页面。图中照片、相册、发现为一级界面,从视频相册进入二级内容界面。 + +![一多-2-2](figures/一多-2-2.png) + +多设备设计:可转化导航类控件到符合设备体验的位置上。默认设备上使用Tab导航,PAD和PC使用侧边Tab导航,智慧屏使用顶部Tab导航。 + +![一多-2-3](figures/一多-2-3.png) + +**层级导航** + +层级导航结构由父页面和子页面组成。父页面可以有一个或多个子页面。每个子页面都有一个父页面。 + +层级导航适用于多层级的复杂结构。层级结构深的内容,用户访问的路径变长,效率降低,可以通过适当的层级穿透设计(例如:控制中心中的蓝牙开关,解决了进“设置-蓝牙”界面设置操作路径过长的问题)解决此问题。 + +使用场景:页面存在上下级关系的应用。 + +![zh-cn_image_0000001224173138](figures/zh-cn_image_0000001224173138.jpg) + +例如:通过从内容进入后经返回键返回之前的页面。 + +![一多-2-5](figures/一多-2-5.png) + +多设备设计:可以考虑将上下层级的界面在同一界面展示。默认设备和智慧屏上使用上下层级关系。平板和PC使用上分栏的方式展示内容。 + +![一多-2-6](figures/一多-2-6.png) + +**混合导航** + +在实际应用设计中,仅使用平级或层级导航可能无法应对更复杂的业务结构。此时需区分不同页面的导航关系,对同等地位或同等层级的页面使用平级导航结构,对具有复杂关系的页面使用层级导航结构。 + +使用场景:应用由几个同等级的模块组成,每个模块又有上下层级关系页面。 + +![zh-cn_image_0000001268653317](figures/zh-cn_image_0000001268653317.jpg) + +多设备设计:可以根据平级导航、层级导航自身的设计规则综合运用,一般平级导航优先级比层级高。 + +![混合导航](figures/混合导航.png) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/page-design.md b/zh-cn/application-dev/key-features/multi-device-app-dev/page-design.md index f475763ab85aa43dad321dbd296ded5d1b776221..871966d67e48357de6c6fdb119b24a32de07509f 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/page-design.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/page-design.md @@ -1,134 +1,136 @@ -# 应用页面结构设计 - - -## 通用页面结构 - -应用程序由多个页面组成。我们将常见的页面进行了梳理,总结了以下常用的页面结构。 - -**启动页面** - -针对内容型应用,应用首页内容的获取需要花费一定的时间,此时可以使用启动页缓解页面加载内容的等待感。启动页可以展示应用的品牌形象或者广告,避免让用户等待过长时间。没有网络加载内容的应用,不需要使用启动页。 - -![zh-cn_image_0000001317205637](figures/zh-cn_image_0000001317205637.png) - -用户总是希望第一时间看到应用内容,因此在页面加载完成后,需要及时呈现内容。 - -从后台加载应用时,不应该显示启动页。当应用被切换到后台后,再从后台加载回来时,不应该再次显示启动页。应用需要保留应用的状态,以便从后台恢复,方便用户继续浏览。 - -**列表内容页面** - -列表内容页面通常用于文字和数据的展示,利于提升使用效率。 - -![zh-cn_image_0000001268605598](figures/zh-cn_image_0000001268605598.png) - -列表应该按照一定的逻辑排序,便于用户浏览和操作。例如:按字母顺序排序、按时间排序。 - -列表应该是同类项的集合,应该对外呈现一致的布局样式。常见的是单行列表、双行列表和三行列表。 - -列表显示的内容要主次分明,用户一眼就能关注到重要的信息和操作。 - -**网格内容页面** - -网格内容页面通常用于图片和视频的展示,利于沉浸浏览内容。 - -![zh-cn_image_0000001268445650](figures/zh-cn_image_0000001268445650.png) - -网格视图显示同等重要的项目,具有统一的布局。 - -网格视图以图像为主组织内容。例如图库中用网格视图展示图片。 - -网格视图可以辅以文字和操作。例如应用市场中使用网格展示应用程序图标、简单描述和下载按钮。 - -网格视图应该考虑响应式布局。在横竖屏切换时,网格视图应该能够调整网格的数量以适应页面的宽度变化。 - -**多选页面** - -多选页面是对页面内的数据多项选择,然后进行批量处理。常见的是针对列表的多项选择或宫格的多项选择。 - -![zh-cn_image_0000001268125810](figures/zh-cn_image_0000001268125810.png) - -**详情页面** - -详情页用于展示应用的详细描述和操作。 - -![zh-cn_image_0000001317325613](figures/zh-cn_image_0000001317325613.png) - -**空页面** - -在页面内没有数据的时候,使用空页面。 - -![zh-cn_image_0000001317485577](figures/zh-cn_image_0000001317485577.png) - -**设置页面** - -设置页面通常是一个模块所有设置项的聚合。 - -![zh-cn_image_0000001268285682](figures/zh-cn_image_0000001268285682.png) - -**我的页面** - -针对内容型应用,可以提供我的页面,用于承载用户的信息和资产内容。 - -![zh-cn_image_0000001317085761](figures/zh-cn_image_0000001317085761.png) - -**关于页面** - -关于页面用于呈现应用的基本情况,包括联系方式,法律条款等内容。 - -![zh-cn_image_0000001317205645](figures/zh-cn_image_0000001317205645.png) - - -## 垂类页面结构 - -垂类是指垂直领域,为特定的人群提供特定的服务,属于应用的细分类别。例如:华为音乐、网易云音乐等属于音乐类,华为视频、优酷等属于视频类,快手、抖音等属于直播类。垂类页面结构是在特定领域长期使用的过程中,形成的广受用户接受和理解的页面结构。 - -例如: - -音乐类应用都有音乐歌单、音乐专辑、音乐播放界面。 - -视频类应用都有视频详情和视频播放界面。 - -直播类应用,都有瀑布流推荐和直播界面。 - -常见的垂类页面结构有: - -- 音乐播放页面 - -- 专辑详情页面 - -- 视频详情页面 - -- 视频播放页面 - -**音乐播放界面** - -音乐类应用中的播放器界面,该界面通常有音乐操控(播放,暂停,上一首,下一首)、歌词显示等功能。 - -![zh-cn_image_0000001268605602](figures/zh-cn_image_0000001268605602.png) - -**专辑详情页** - -音乐类应用中的音乐专辑详情界面,该界面通常有专辑介绍、专辑包含的歌曲列表等功能。 - -![zh-cn_image_0000001268445654](figures/zh-cn_image_0000001268445654.png) - -**视频详情页面** - -视频类应用的视频详情界面,该界面通常有视频播放器、视频剧集显示、视频简介等功能。 - -![zh-cn_image_0000001268125814](figures/zh-cn_image_0000001268125814.png) - -**视频播放界面** - -视频类应用的视频播放界面,该界面通常有视频画面预览、播放控制等功能。 - -![zh-cn_image_0000001317325617](figures/zh-cn_image_0000001317325617.png) - - -## 特殊页面结构 - -部分应用界面在差异较大的设备间切换,无法使用自适应和响应式布局设计方法进行适配,从用户预期上也需要调整应用架构时,将需要做特殊适配。 - -例如,同时具有底部Tab和子页签的页面,在大屏上应考虑将底部入口置于顶部工具栏或与子页签融合。 - -![zh-cn_image_0000001317485581](figures/zh-cn_image_0000001317485581.png) +# 应用页面结构设计 + + +## 通用页面结构 + +应用程序由多个页面组成。我们将常见的页面进行了梳理,总结了以下常用的页面结构。 + +**启动页面** + +针对内容型应用,应用首页内容的获取需要花费一定的时间,此时可以使用启动页缓解页面加载内容的等待感。启动页可以展示应用的品牌形象或者广告,避免让用户等待过长时间。没有网络加载内容的应用,不需要使用启动页。 + +![一多-应用架构-启动页](figures/一多-应用架构-启动页.png) + +用户总是希望第一时间看到应用内容,因此在页面加载完成后,需要及时呈现内容。 + +从后台加载应用时,不应该显示启动页。当应用被切换到后台后,再从后台加载回来时,不应该再次显示启动页。应用需要保留应用的状态,以便从后台恢复,方便用户继续浏览。 + +**列表内容页面** + +列表内容页面通常用于文字和数据的展示,利于提升使用效率。 + +![一多-应用架构-列表视觉图](figures/一多-应用架构-列表视觉图.png) + +列表应该按照一定的逻辑排序,便于用户浏览和操作。例如:按字母顺序排序、按时间排序。 + +列表应该是同类项的集合,应该对外呈现一致的布局样式。常见的是单行列表、双行列表和三行列表。 + +列表显示的内容要主次分明,用户一眼就能关注到重要的信息和操作。 + +**网格内容页面** + +网格内容页面通常用于图片和视频的展示,利于沉浸浏览内容。 + +![一多-应用架构-网格视图](figures/一多-应用架构-网格视图.png) + +网格视图显示同等重要的项目,具有统一的布局。 + +网格视图以图像为主组织内容。例如图库中用网格视图展示图片。 + +网格视图可以辅以文字和操作。例如应用市场中使用网格展示应用程序图标、简单描述和下载按钮。 + +网格视图应该考虑响应式布局。在横竖屏切换时,网格视图应该能够调整网格的数量以适应页面的宽度变化。 + +**多选页面** + +多选页面是对页面内的数据多项选择,然后进行批量处理。常见的是针对列表的多项选择或宫格的多项选择。 + +![应用架构-常用页面结构-通用页面结构-多选页面低保真](figures/应用架构-常用页面结构-通用页面结构-多选页面低保真.png) + +**详情页面** + +详情页用于展示应用的详细描述和操作。 + +![应用架构-常用页面结构-通用页面结构-详情页面低保真](figures/应用架构-常用页面结构-通用页面结构-详情页面低保真.png) + +**空页面** + +在页面内没有数据的时候,使用空页面。 + +![一多-应用架构-空页面](figures/一多-应用架构-空页面.png) + +**设置页面** + +设置页面通常是一个模块所有设置项的聚合。 + +![一多-应用架构-设置](figures/一多-应用架构-设置.png) + +**我的页面** + +针对内容型应用,可以提供我的页面,用于承载用户的信息和资产内容。 + +![一多-应用架构-我的页面](figures/一多-应用架构-我的页面.png) + +**关于页面** + +关于页面用于呈现应用的基本情况,包括联系方式,法律条款等内容。 + +![一多-应用架构-关于](figures/一多-应用架构-关于.png) + + +## 垂类页面结构 + +垂类是指垂直领域,为特定的人群提供特定的服务,属于应用的细分类别。例如:华为音乐、网易云音乐等属于音乐类,华为视频、优酷等属于视频类,快手、抖音等属于直播类。垂类页面结构是在特定领域长期使用的过程中,形成的广泛被用户接受和理解的页面结构。 + +例如: + +音乐类应用都有音乐歌单,音乐专辑,音乐播放界面。 + +视频类应用都有视频详情和视频播放界面。 + +直播类应用,都有瀑布流推荐和直播界面。 + +... + +常见的垂类页面结构有: + +- 音乐播放页面 + +- 专辑详情页面 + +- 视频详情页面 + +- 视频播放页面 + +**音乐播放界面** + +音乐类应用中的播放器界面,该界面通常有音乐操控(播放,暂停,上一首,下一首)、歌词显示等功能。 + +![应用架构-常用页面结构-垂类页面结构-音乐播放低保真](figures/应用架构-常用页面结构-垂类页面结构-音乐播放低保真.png) + +**专辑详情页** + +音乐类应用中的音乐专辑详情界面,该界面通常有专辑介绍、专辑包含的歌曲列表等功能。 + +![应用架构-常用页面结构-垂类页面结构-歌单详情低保真](figures/应用架构-常用页面结构-垂类页面结构-歌单详情低保真.png) + +**视频详情页面** + +视频类应用的视频详情界面,该界面通常有视频播放器、视频剧集显示、视频简介等功能。 + +![一多-应用架构-视频详情](figures/一多-应用架构-视频详情.png) + +**视频播放界面** + +视频类应用的视频播放界面,该界面通常有视频画面预览、播放控制等功能。 + +![一多-应用架构-视频播放](figures/一多-应用架构-视频播放.png) + + +## 特殊页面结构 + +部分应用界面在差异较大的设备间切换,无法使用自适应和响应式布局设计方法进行适配,从用户预期上也需要调整应用架构时,将需要做特殊适配。 + +例如,同时具有底部Tab和子页签的页面,在大屏上应考虑将底部入口置于顶部工具栏或与子页签融合。 + +![特殊页面结构](figures/特殊页面结构.png) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/page-development-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/page-development-intro.md new file mode 100644 index 0000000000000000000000000000000000000000..369f19ff11d70956b4bd62f094cbafa9b6f4ae8f --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/page-development-intro.md @@ -0,0 +1,24 @@ +# 简介 + + +本章介绍如何使用方舟开发框架“一多”能力,开发出在多设备上正常显示的页面。方舟开发框架推荐开发者使用声明式开发范式开发应用,故本章的内容和示例都主要基于声明式开发范式。本章主要包含如下内容: + + +- [布局能力](adaptive-layout.md) + + 布局决定了页面中的元素按照何种方式排布及显示,是页面设计及开发过程中首先需要考虑的问题。一般情况下,可以通过页面(或自定义组件)内的组件结构(组件个数、组件的父子/兄弟关系、组件类型、组件的相对位置)来判断使用何种布局能力。 + + - 对于随尺寸变化组件结构相同的场景,可以在开发过程中灵活使用[自适应布局能力](adaptive-layout.md)来达到目标效果。 + - 对于随尺寸变化组件结构不同的场景,更适合使用[响应式布局能力](responsive-layout.md)来实现不同尺寸下的不同显示的效果。 + +- [交互归一](interaction-event-normalization.md) + +- [多态组件](polymorphic-controls.md) + +- [资源使用](resource-usage.md) + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 开发多设备上同一页面时,建议开发者多使用[自定义组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-component-based-component.md),既可以增加代码的可读性和可维护性,同时也可以尽可能的实现代码复用。 +> +> - 本章中涉及的示例代码均可以在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev)中获取,感兴趣的开发者可以自行下载、运行及查看效果。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/page-development.md b/zh-cn/application-dev/key-features/multi-device-app-dev/page-development.md new file mode 100644 index 0000000000000000000000000000000000000000..26684e7413a384b7966b5e2d30a655bed796c7c1 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/page-development.md @@ -0,0 +1,13 @@ +# 页面开发的一多能力介绍 + + + +- **[简介](page-development-intro.md)** + +- **[布局能力](layout.md)** + +- **[交互归一](interaction-event-normalization.md)** + +- **[多态组件](polymorphic-controls.md)** + +- **[资源使用](resource-usage.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-components.md b/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-components.md deleted file mode 100644 index a7a6573bcf523295024a60c091a10258863e96c1..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-components.md +++ /dev/null @@ -1,8 +0,0 @@ -# 多态组件 - - -方舟开发框架不仅提供了多种基础组件,如文本显示、图片显示、按键交互等。并且针对不同类型设备进行了组件设计,提供了组件在不同平台上的样式适配能力,此种组件称为“多态组件”。开发者在使用多态组件时,无需考虑设备差异,只需关注功能实现即可。 - - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> OpenHarmony上的多态组件能力正在逐步补齐中。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-controls.md b/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-controls.md new file mode 100644 index 0000000000000000000000000000000000000000..8367fdae021a1178e636f0fabf664657082534d6 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/polymorphic-controls.md @@ -0,0 +1,8 @@ +# 多态组件 + + +方舟开发框架不仅提供了多种基础组件(如文本显示、图片显示、按键交互等),并且针对不同类型设备分别进行了适配。同一组件在不同的设备上会呈现出不同的形态(即视觉、交互、动效等可能有差异),称为“多态组件”。开发者在使用多态组件时,无需考虑设备差异,只需关注功能实现即可。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> OpenHarmony上的多态组件能力正在逐步补齐中。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/resource-usage.md b/zh-cn/application-dev/key-features/multi-device-app-dev/resource-usage.md index 20129df52a83ba41e72039ef1ee3320624da9b66..fe0055c25c6344f7accaded148b7775731ea2c08 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/resource-usage.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/resource-usage.md @@ -1,143 +1,128 @@ -# 资源使用 - - -在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种方式处理: - - -- [自定义资源](#自定义资源):借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。 - -- [系统资源](#系统资源):开发者直接使用系统预置的资源定义(即分层参数)。 - - -## 自定义资源 - - -### 资源文件介绍 - -开发者可以在项目工程的resources目录中创建指定类型的资源文件,通过”key-value”的形式定义资源,同时可以借助资源限定词能力,定义同一资源在不同设备(默认设备、智慧屏等)或同一设备不同配置(横竖屏、深浅色等)下的表现。工程内的resources目录按照两级目录的形式来组织: - -- 一级目录为base目录、限定词目录以及rawfile目录 - - base目录是默认存在的目录。当应用的resources资源目录中没有与设备状态匹配的限定词目录时,会自动引用该目录中的资源文件。 - - 限定词目录需要开发者自行创建,其可以由一个或多个表征应用场景或设备特征的限定词组合而成,包括移动国家码和移动网络码、语言、文字、国家或地区、横竖屏、设备类型、颜色模式和屏幕密度等维度,限定词之间通过下划线(_)或者中划线(-)连接。 - - 在引用rawfile中的资源时,不会根据系统的状态去匹配,rawfile目录中可以直接存放资源文件。 - -- 二级目录为资源目录 - - 用于存放字符串、颜色、浮点数等基础元素,以及媒体等资源文件。 - - 当前支持的文件和资源类型如下: - | 文件名 | 资源类型 | - | -------- | -------- | - | color.json | 颜色资源。 | - | float.json | 间距、圆角、字体等资源。 | - | string.json | 字符串资源。 | - | plural.json | 字符串资源。 | - | media目录 | 图片资源 | - - -### 资源文件使用 - -在工程中,通过 "$r('app.type.name')" 的形式引用应用资源。app代表是应用内resources目录中定义的资源;type 代表资源类型(或资源的存放位置),可以取 color、float、string、plural和media,name代表资源命名,由开发者定义资源时确定。 - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> - 可以查看[声明式开发范式资源访问](../../ui/ts-resource-access.md),了解资源访问的更多细节。 -> -> - 类Web开发范式的资源文件路径及资源限定词的使用与声明式范式不同,详情请参考[类Web开发范式资源限定与访问](../../ui/js-framework-resource-restriction.md)及[类Web开发范式文件组织](../../ui/js-framework-file.md)。 - - -### 示例 - -按照如下说明,配置工程resources目录中的json资源文件(如文件不存在,需手工创建)。另外,准备两张不同的图片,分别放置于resources/base/media/my_image.jpg及resources/tablet/media/my_image.jpg路径下。 - - -```ts -//resources/base/element/string.json - { - "string":[ - { - "name":"my_string", - "value":"default" - } - ] - } - //resources/base/element/color.json - { - "color":[ - { - "name":"my_color", - "value":"#ff0000" - } - ] - } - //resources/base/element/float.json - { - "float":[ - { - "name":"my_float", - "value":"60vp" - } - ] - } - - //resources/tablet/element/string.json - { - "string":[ - { - "name":"my_string", - "value":"tablet" - } - ] - } - //resources/tablet/element/color.json - { - "color":[ - { - "name":"my_color", - "value":"#0000ff" - } - ] - } - //resources/tablet/element/float.json - { - "float":[ - { - "name":"my_float", - "value":"80vp" - } - ] - } -``` - -![zh-cn_image_0000001267577314](figures/zh-cn_image_0000001267577314.png) - -页面源码如下: - - -```ts -@Entry -@Component -struct Index { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - Text($r("app.string.my_string")) - .fontSize($r("app.float.my_float")) - .fontColor($r("app.color.my_color")) - Image($r("app.media.my_image")) - .width(100) - .height(100) - } - .width('100%') - .height('100%') - } -} -``` - - -## 系统资源 - -除了自定义资源,开发者也可以使用系统中预定义的资源(即[分层参数](visual-style-basics.md),同一资源ID在设备类型、深浅色等不同配置下有不同的取值)。 - -在开发过程中,分层参数的用法与资源限定词基本一致。开发者可以通过"$r('sys.type.resource_id')"的形式引用系统资源。sys代表是系统资源;type代表资源类型,值可以取color、float、string和media;resource_id代表资源id。 - -可以访问本文"[资源](resource.md)",获取OHOS上支持的系统资源ID及其在不同配置下的取值。也可以访问[OpenHarmony/resources代码仓](https://gitee.com/openharmony/resources/tree/master/systemres/main/resources),了解OpenHarmony系统中预置的分层参数资源,可以发现这里目录结构与工程中的resources目录类似,也是通过资源限定词匹配不同的设备或设备状态。 - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> 仅声明式开发范式支持使用分层参数,类Web开发范式不支持。 +# 资源使用 + + +在页面开发过程中,经常需要用到颜色、字体、间距、图片等资源,在不同的设备或配置中,这些资源的值可能不同。有两种方式处理: + + +- [应用资源](#应用资源):借助资源文件能力,开发者在应用中自定义资源,自行管理这些资源在不同的设备或配置中的表现。 + +- [系统资源](#系统资源):开发者直接使用系统预置的资源定义(即分层参数)。 + + +## 应用资源 + + +### 资源文件介绍 + +应用开发中使用的各类自定义资源文件,需要统一存放于应用的resources目录下,便于使用和维护。resources目录包括两大类目录,一类为base目录与限定词目录,另一类为rawfile目录,其基础目录结构如下所示。 + + +``` +resources +|---base // 默认存在的目录 +| |---element +| | |---string.json +| |---media +| | |---icon.png +|---en_GB-vertical-car-mdpi // 限定词目录示例,需要开发者自行创建 +| |---element +| | |---string.json +| |---media +| | |---icon.png +|---rawfile // rawfile目录 +``` + +base目录默认存在,而限定词目录需要开发者自行创建,其名称可以由一个或多个表征应用场景或设备特征的限定词组合而成。应用使用某资源时,系统会根据当前设备状态优先从相匹配的限定词目录中寻找该资源。只有当resources目录中没有与设备状态匹配的限定词目录,或者在限定词目录中找不到该资源时,才会去base目录中查找。rawfile是原始文件目录,它不会根据设备状态去匹配不同的资源,故不在本文的讨论范文内。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 请访问[声明式开发范式资源文件分类](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ui-ts-basic-resource-file-categories.md),了解限定词目录的命名规则、创建流程、匹配规则等,本文不展开介绍。 +> +> - 没有设备状态匹配的限定词目录,或者在限定词目录中找不到目标资源时,会继续在base目录中查找。**强烈建议对于所有应用自定义资源都在base目录中定义默认值**,防止出现找不到资源值的异常场景。 +> +> - 类Web开发范式的资源文件路径及资源限定词的使用与声明式范式不同,详情请参考[类Web开发范式资源限定与访问](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/js-framework-resource-restriction.md)及[类Web开发范式文件组织](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/js-framework-file.md)。 + +base目录与限定词目录下面可以创建资源组目录(包括element、media等),用于存放特定类型的资源文件。 + + | 资源组目录 | 目录说明 | 资源文件 | +| -------- | -------- | -------- | +| element | 表示元素资源,以下每一类数据都采用相应的JSON文件来表征。
- boolean,布尔型
- color,颜色
- float,浮点型
- intarray,整型数组
- integer,整型
- pattern,样式
- plural,复数形式
- strarray,字符串数组
- string,字符串 | element目录中的文件名称建议与下面的文件名保持一致。每个文件中只能包含同一类型的数据。
- boolean.json
- color.json
- float.json
- intarray.json
- integer.json
- pattern.json
- plural.json
- strarray.json
- string.json | +| media | 表示媒体资源,包括图片、音频、视频等非文本格式的文件。 | 文件名可自定义,例如:icon.png。 | + +在element目录的各个资源文件中,以“name-value”的形式定义资源,如下所示。而在media目录中,直接以文件名作为name,故开发者将文件放入media目录即可,无需再额外定义name。 + + +``` +// color.json +{ + "color": [ + { + "name": "color_red", + "value": "#ffff0000" + }, + { + "name": "color_blue", + "value": "#ff0000ff" + } + ] +} +``` + + +### 访问应用资源 + +在工程中,通过 "$r('app.type.name')" 的形式引用应用资源。app代表是应用内resources目录中定义的资源;type 代表资源类型(或资源的存放位置),可以取 color、float、string、plural和media,name代表资源命名,由开发者添加资源时确定。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 可以查看[声明式范式访问应用资源](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-resource-access.md),了解资源访问的更多细节。 + + +### 示例 + +在应用的resources目录下,创建名为tablet的限定词子目录,并按照下表所示,在base目录和tablet限定词目录中添加相应的资源。 + + | 资源名称 | 资源类型 | base目录中资源值 | 限定词目录(tablet)中资源值 | +| -------- | -------- | -------- | -------- | +| my_string | string | default | tablet | +| my_color | color | \#ff0000 | \#0000ff | +| my_float | float | 60vp | 80vp | +| my_image | media | my_image.png(太阳图标) | my_image.png(月亮图标) | + +在代码中通过 "$r('app.type.name')" 的形式使用应用资源,并分别在默认设备和平板上查看代码的运行效果,可以发现同一资源在不同设备上的取值不同。 + +![zh-cn_image_0000001325731389](figures/zh-cn_image_0000001325731389.png) + + +``` +@Entry +@Component +struct Index { + build() { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text($r("app.string.my_string")) + .fontSize($r("app.float.my_float")) + .fontColor($r("app.color.my_color")) + Image($r("app.media.my_image")) + .width(100) + .height(100) + } + .width('100%') + .height('100%') + } +} +``` + + +## 系统资源 + +除了自定义资源,开发者也可以使用系统中预定义的资源(即[分层参数](visual-basics.md),同一资源ID在设备类型、深浅色等不同配置下有不同的取值)。 + +在开发过程中,分层参数的用法与资源限定词基本一致。开发者可以通过"$r('sys.type.resource_id')"的形式引用系统资源。sys代表是系统资源;type代表资源类型,值可以取color、float、string和media;resource_id代表资源id。 + +可以查看本文[应用UX设计中关于资源的介绍](design-resources.md),获取OpenHarmony支持的系统资源ID及其在不同配置下的取值。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 仅声明式开发范式支持使用分层参数,类Web开发范式不支持。 +> +> - 系统资源可以保证不同团队开发出的应用有较为一致的视觉风格。对于系统预置应用,强烈建议使用系统资源;对于三方应用,可以根据需要选择使用系统资源或自定义应用资源。 +> +> - 可以查看[OpenHarmony/resources代码仓](https://gitee.com/openharmony/resources/tree/master/systemres/main/resources)了解系统预置资源的实现,这里的目录结构与工程中的resources目录类似,也是通过资源限定词匹配不同的设备或设备状态。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/resource.md b/zh-cn/application-dev/key-features/multi-device-app-dev/resource.md deleted file mode 100644 index f5ef4751beff2db297eecf5c097a796cdc689adb..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/resource.md +++ /dev/null @@ -1,20 +0,0 @@ -# 资源 - -为方便UX设计师以及开发者使用[分层参数](visual-style-basics.md),本文特提供 [OpenHarmony_系统资源分层设计表_V1.0.xlsm](OpenHarmony_系统资源分层设计表_V1.0.xlsm)。 - -系统资源分层设计表列出了当前OpenHarmony中可用系统资源id及其在不同类型设备上的取值,它由六张子表组成,各个子表的含义如下所示。 - -| 表格 | 简介 | -| ------------------ | ------------------------------------------------------------ | -| 应用色彩参数 | 在**应用开发**过程中可以使用的**色彩**相关的系统资源。 | -| 应用圆角参数 | 在**应用开发**过程中可以使用的**圆角**相关的系统资源。 | -| 应用字体参数 | 在**应用开发**过程中可以使用的**字体**相关的系统资源。 | -| 应用间距参数 | 在**应用开发**过程中可以使用的**间距**相关的系统资源。 | -| 服务卡片参数 | 在**服务卡片开发**过程中可以使用的系统资源。 | -| 不透明度数值速查表 | 用于将不透明度在**百分比表示形式**和**十六进制表示形式**之间快速转换的速查表。 | - -> ![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 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout-cases.md b/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout-cases.md deleted file mode 100644 index 40c854457c23656c460bcbbbb7331165854adb6a..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout-cases.md +++ /dev/null @@ -1,202 +0,0 @@ -# 典型场景 - - -当基本的自适应布局无法满足多终端上屏幕的体验要求时,我们可以针对不同终端的屏幕特点,借助栅格系统和媒体查询能力,实现更复杂的布局效果。 - - -## 缩进布局 - -在上一小节“栅格系统”中,我们介绍了四种不同的设备宽度类型,在不同宽度类型的设备中,默认的Margin、Gutter及Column数量不同。借助栅格系统,我们可以很方便的在不同宽度的设备上实现不同的缩进效果。 - - -### 示例 - -![zh-cn_image_0000001317091985](figures/zh-cn_image_0000001317091985.png) - - -```ts -@Entry -@Component -struct IndentationSample { - build() { - Row() { - GridContainer() { - Column() { - ForEach([0, 1, 2, 4], () => { - Column() { - ItemContent() - }.useSizeType({ xs: 2, sm: 4, md: 6, lg: 8 }) - }) - } - } - } - .alignItems(VerticalAlign.Center) - .height('100%') - .backgroundColor('#F1F3F5') - } -} - -@Component -struct ItemContent { - build() { - Column() { - Row() { - Row() {} - .width(28).height(28).borderRadius(14).margin({ right: 15 }) - .backgroundColor('#E4E6E8') - Row() {} - .width('30%').height(20).borderRadius(4) - .backgroundColor('#E4E6E8') - }.width('100%').height(28) - - Row() {} - .width('100%').height(68).borderRadius(16).margin({ top: 12 }) - .backgroundColor('#E4E6E8') - } - .height(128) - .borderRadius(24) - .backgroundColor('#FFFFFF') - .padding({ top: 12, bottom: 12, left: 18, right: 18 }) - .margin({ bottom: 12 }) - } -} -``` - - -## 挪移布局 - -挪移布局是栅格和折行能力的结合。当屏幕宽度发生改变,达到预设的断点时,栅格中子元素占据的列数会随着开发者的配置发生改变。当一行中的列数超过栅格组件在该断点的指定值时,可以自动换行。借助挪移布局,我们可以很方便的实现内容尺寸及相对位置的调整。 - - -### 示例 - -当屏幕宽度发生变化时,图片和文字由”上下布局”切换为”左右布局”。 - -![zh-cn_image_0000001317211889](figures/zh-cn_image_0000001317211889.png) - - -```ts -@Entry -@Component -struct DiversionSample { - build() { - Row() { - GridContainer() { - Flex({ - direction: FlexDirection.Row, - alignItems: ItemAlign.Center, - justifyContent: FlexAlign.Center, - wrap: FlexWrap.Wrap - }) { - Row() { - Image($r('app.media.illustrator')) - } - .aspectRatio(1) - .useSizeType({ xs: 2, sm: 4, md: 4, lg: 6 }) - - Flex({ - direction: FlexDirection.Column, - alignItems: ItemAlign.Center, - justifyContent: FlexAlign.Center - }) { - Text('用户体验改进计划') - .textAlign(TextAlign.Center) - .fontSize(20) - .fontWeight(FontWeight.Medium) - Text('用户体验改进计划通过系统、应用分析、故障诊断,提升华为的产品和服务质量') - .textAlign(TextAlign.Center) - .fontSize(14) - .fontWeight(FontWeight.Medium) - } - .height(100) - .useSizeType({ xs: 2, sm: 4, md: 4, lg: 6 }) - } - } - - }.height('100%') - .alignItems(VerticalAlign.Center) - .backgroundColor('#F1F3F5') - } -} -``` - - -## 重复布局 - -充分利用屏幕尺寸优势,当屏幕变宽时,增加显示元素的数量。注意这种场景下,组件的数量发生了变化。可以使用媒体查询改变元素数量,同时借助栅格系统设置这些元素在不同宽度设备下的尺寸和位置。 - - -### 示例 - -![zh-cn_image_0000001268611858](figures/zh-cn_image_0000001268611858.png) - - -```ts -import mediaquery from '@ohos.mediaquery' - -@Entry -@Component -struct RepeatSample { - @State isWidescreen: boolean = false; - private listener: mediaquery.MediaQueryListener = mediaquery.matchMediaSync('(width > 1200)'); - - onWidthChange = (mediaQueryResult) => { - if (mediaQueryResult.matches) { - this.isWidescreen = true; - } else { - this.isWidescreen = false; - } - } - - private aboutToAppear(): void { - this.listener.on('change', this.onWidthChange); - } - - private aboutToDisappear(): void { - this.listener.off('change', this.onWidthChange); - } - - build() { - Row() { - GridContainer() { - ForEach([0, 1, 2, 3], () => { - Row() { - Column() { RepeatItemContent() } - .useSizeType({ - xs: { span: 2, offset: 0 }, sm: { span: 4, offset: 0 }, - md: { span: 4, offset: 0 }, lg: { span: 6, offset: 0 } - }) - - if (this.isWidescreen) { - Column() { RepeatItemContent() } - .useSizeType({ - md: { span: 4, offset: 4 }, lg: { span: 6, offset: 6 } - }) - } - } - }) - } - } - .height('100%') - .backgroundColor('#F1F3F5') - } -} - -@Component -struct RepeatItemContent { - build() { - Flex() { - Row() {}.width(43).height(43).borderRadius(12).backgroundColor('#E4E6E8') - Flex({ alignItems: ItemAlign.Start, direction: FlexDirection.Column, justifyContent: FlexAlign.SpaceAround }) { - Row() {}.height(10).width('100%').backgroundColor('#E4E6E8') - Row() {}.height(10).backgroundColor('#E4E6E8').width('50%') - }.flexGrow(1).margin({ left: 13 }) - } - .padding({ top: 13, bottom: 13, left: 13, right: 37 }) - .height(69) - .backgroundColor('#FFFFFF') - .margin({ bottom: 12 }) - .borderRadius(24) - } -} -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md b/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md new file mode 100644 index 0000000000000000000000000000000000000000..2d638ff1ded5b48155366727dee7f38478ace8a2 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/responsive-layout.md @@ -0,0 +1,736 @@ +# 响应式布局 + + +自适应布局可以保证窗口尺寸在一定范围内变化时,页面的显示是正常的。但是将窗口尺寸变化较大时(如窗口宽度从400vp变化为1000vp),仅仅依靠自适应布局可能出现图片异常放大或页面内容稀疏、留白过多等问题,此时就需要借助响应式布局能力调整页面结构。 + + +响应式布局是指页面内的元素可以根据特定的特征(如窗口宽度、屏幕方向等)自动变化以适应外部容器变化的布局能力。响应式布局中最常使用的特征是窗口宽度,可以将窗口宽度划分为不同的范围(下文中称为断点)。当窗口宽度从一个断点变化到另一个断点时,改变页面布局(如将页面内容从单列排布调整为双列排布甚至三列排布等)以获得更好的显示效果。 + + +当前OpenHarmony提供了如下三种响应式布局能力,后文中我们将依次展开介绍。 + + + | 响应式布局能力 | 简介 | +| -------- | -------- | +| [断点](#断点) | 将窗口宽度划分为不同的范围(即断点),监听窗口尺寸变化,当断点改变时同步调整页面布局。 | +| [媒体查询](#媒体查询) | 媒体查询支持监听窗口宽度、横竖屏、深浅色、设备类型等多种媒体特征,当媒体特征发生改变时同步调整页面布局。 | +| [栅格布局](#栅格布局) | 栅格组件将其所在的区域划分为有规律的多列,通过调整不同断点下的栅格组件的参数以及其子组件占据的列数等,实现不同的布局效果。 | + + +## 断点 + +断点以应用窗口宽度为切入点,将应用窗口在宽度维度上分成了几个不同的区间即不同的断点,在不同的区间下,开发者可根据需要实现不同的页面布局效果。具体的断点如下所示。 + + | 断点名称 | 取值范围(vp) | +| -------- | -------- | +| xs | [0, 320) | +| sm | [320, 520) | +| md | [520, 840) | +| lg | [840, +∞) | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - 以设备屏幕宽度作为参照物,也可以实现类似的效果。考虑到应用可能以非全屏窗口的形式显示,以应用窗口宽度为参照物更为通用。 +> +> - 开发者可以根据实际使用场景决定适配哪些断点。如xs断点对应的一般是智能穿戴类设备,如果确定某页面不会在智能穿戴设备上显示,则可以不适配xs断点。 + +OpenHarmony提供了多种方法,判断应用当前处于何种断点,进而可以调整应用的布局。常见的监听断点变化的方法如下所示: + +- 获取窗口对象并监听窗口尺寸变化 + +- 通过媒体查询监听应用窗口尺寸变化 + +- 借助栅格组件能力监听不同断点的变化 + +本小节中,先介绍如何通过窗口对象监听断点变化,后续的媒体查询及栅格章节中,将进一步展开介绍另外两种方法。 + +通过窗口对象监听断点变化的核心是获取窗口对象及注册窗口尺寸变化的回调函数。 + +1. 在Ability的[onWindowStageCreate](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ability/stage-ability.md)生命周期回调中,获取并记录[窗口](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-window.md)对象。 + + ``` + // MainAbility.ts + import window from '@ohos.window' + + export default class MainAbility extends Ability { + ... + onWindowStageCreate(windowStage) { + window.getTopWindow(this.context).then((windowObj) => { + AppStorage.SetOrCreate('windowObj', windowObj) + }) + } + ... + } + ``` + +2. 在页面中,通过窗口对象获取启动时的应用窗口宽度,同时注册回调函数监听窗口尺寸变化。 + + ``` + @Entry + @Component + struct Index { + @State private currentBreakpoint: string = 'sm' + + private updateBreakpoint(windowWidth) { + if (windowWidth < 320) { + this.currentBreakpoint = 'xs' + return + } + if (windowWidth < 520) { + this.currentBreakpoint = 'sm' + return + } + if (windowWidth < 840) { + this.currentBreakpoint = 'md' + return + } + this.currentBreakpoint = 'lg' + } + + aboutToAppear() { + let windowObj: window.Window = AppStorage.Get('windowObj') + // 获取应用启动时的窗口尺寸 + windowObj.getProperties().then((windowProperties) => { + this.updateBreakpoint(px2vp(windowProperties.windowRect.width)) + }) + + // 注册回调函数,监听窗口尺寸变化 + windowObj.on('windowSizeChange', (data) => { + this.updateBreakpoint(px2vp(data.width)) + }); + } + + aboutToDisappear() { + let windowObj: window.Window = AppStorage.Get('windowObj') + windowObj.off('windowSizeChange') + } + + build() { + Flex({justifyContent: FlexAlign.Center, alignItems: ItemAlign.Center}) { + Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium) + } + .width('100%') + .height('100%') + } + } + ``` + +3. 运行及验证效果。 + | | | | + | -------- | -------- | -------- | + | ![zh-cn_image_0000001336485520](figures/zh-cn_image_0000001336485520.jpg) | ![zh-cn_image_0000001386645965](figures/zh-cn_image_0000001386645965.jpg) | ![zh-cn_image_0000001386325621](figures/zh-cn_image_0000001386325621.jpg) | + + +## 媒体查询 + + +在实际应用开发过程中,开发者常常需要针对不同类型设备或同一类型设备的不同状态来修改应用的样式。媒体查询提供了丰富的媒体特征监听能力,可以监听应用显示区域变化、横竖屏、深浅色、设备类型等等,因此在应用开发过程中使用的非常广泛。 + + +本小节仅介绍**媒体查询跟断点的结合**,即如何借助媒体查询能力,监听断点的变化,读者可以自行查阅官网中关于[媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ui-ts-layout-mediaquery.md)的相关介绍了解更详细的用法。 + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 类Web开发范式,支持在js文件和css文件中使用媒体查询,请查看[js媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/apis/js-apis-mediaquery.md)和[css媒体查询](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-js/js-components-common-mediaquery.md)了解详细用法。 + + +**示例:** + + +通过媒体查询,监听应用窗口宽度变化,获取当前应用所处的断点值。 + + + | | | | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001336165712](figures/zh-cn_image_0000001336165712.jpg) | ![zh-cn_image_0000001386485617](figures/zh-cn_image_0000001386485617.jpg) | ![zh-cn_image_0000001386805569](figures/zh-cn_image_0000001386805569.jpg) | + + + +``` +// common/breakpointsystem.ets +// 对通过媒体查询监听断点的功能做简单的封装,方便后续使用 +import mediaquery from '@ohos.mediaquery'; + +export class BreakpointType { + sm: T + md: T + lg: T + constructor(sm: T, md: T, lg: T) { + this.sm = sm + this.md = md + this.lg = lg + } + GetValue(currentBreakpoint: string) { + if (currentBreakpoint === 'sm') { + return this.sm + } + if (currentBreakpoint === 'md') { + return this.md + } + if (currentBreakpoint === 'lg') { + return this.lg + } + return undefined + } +} + +export class BreakpointSystem { + private currentBreakpoint: string = 'md' + private smListener: mediaquery.MediaQueryListener + private mdListener: mediaquery.MediaQueryListener + private lgListener: mediaquery.MediaQueryListener + + private updateCurrentBreakpoint(breakpoint: string) { + if (this.currentBreakpoint !== breakpoint) { + this.currentBreakpoint = breakpoint + AppStorage.Set('currentBreakpoint', this.currentBreakpoint) + } + } + private isBreakpointSM = (mediaQueryResult) => { + if (mediaQueryResult.matches) { + this.updateCurrentBreakpoint('sm') + } + } + private isBreakpointMD = (mediaQueryResult) => { + if (mediaQueryResult.matches) { + this.updateCurrentBreakpoint('md') + } + } + private isBreakpointLG = (mediaQueryResult) => { + if (mediaQueryResult.matches) { + this.updateCurrentBreakpoint('lg') + } + } + + public register() { + this.smListener = mediaquery.matchMediaSync("(320vp栅格 + +栅格是多设备场景下通用的辅助定位工具,通过将空间分割为有规律的栅格。栅格可以显著降低适配不同屏幕尺寸的设计及开发成本,使得整体设计和开发流程更有秩序和节奏感,同时也保证多设备上应用显示的协调性和一致性,提升用户体验。 + +![zh-cn_image_0000001224173302](figures/zh-cn_image_0000001224173302.png) + + 栅格的样式由Margin、Gutter、Columns三个属性决定。 +- Margin是相对应用窗口、父容器的左右边缘的距离,决定了内容可展示的整体宽度。 + +- Gutter是相邻的两个Column之间的距离,决定内容间的紧密程度。 + +- Columns是栅格中的列数,其数值决定了内容的布局复杂度。 + +单个Column的宽度是系统结合Margin、Gutter和Columns自动计算的,不需要也不允许开发者手动配置。 + + +### 栅格布局 + +栅格布局就是栅格结合了断点,实现栅格布局能力的组件叫栅格组件。在实际使用场景中,可以根据需要配置不同断点下栅格组件中元素占据的列数,同时也可以调整Margin、Gutter、Columns的取值,从而实现不同的布局效果。 + + | sm断点 | md断点 | +| -------- | -------- | +| ![zh-cn_image_0000001336486244](figures/zh-cn_image_0000001336486244.jpg) | ![zh-cn_image_0000001386646685](figures/zh-cn_image_0000001386646685.jpg) | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - ArkUI在API 9对栅格组件做了重构,推出了新的栅格组件[GridRow](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md)和[GridCol](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcol.md),同时原有的[GridContainer组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridcontainer.md)及[栅格设置](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-grid.md)已经废弃。 +> +> - 本文中提到的栅格组件,如无特别说明,都是指GridRow和GridCol组件。 + + +### 栅格组件的断点 + +栅格组件提供了丰富的断点定制能力。 + +**(一)开发者可以修改断点的取值范围,支持启用最多6个断点。** + +- 基于本文断点小节介绍的推荐值,栅格组件默认提供xs、sm、md、lg四个断点。 + +- 栅格组件支持开发者修改断点的取值范围,除了默认的四个断点,还支持开发者启用xl和xxl两个额外的断点。 + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 断点并非越多越好,通常每个断点都需要开发者“精心适配”以达到最佳显示效果。 + +**示例1:** + +修改默认的断点范围,同时启用xl和xxl断点。 + +图片右下角显示了当前设备屏幕的尺寸(即应用窗口尺寸),可以看到随着窗口尺寸发生变化,栅格的断点也相应发生了改变。(为了便于理解,下图中将设备的DPI设置为160,此时1vp=1px) + +![window3](figures/window3.gif) + + +``` +@Entry +@Component +struct GridRowSample1 { + @State private currentBreakpoint: string = 'unknown' + build() { + // 修改断点的取值范围同时启用更多断点,注意,修改的断点值后面必须加上vp单位。 + GridRow(breakpoints: {value: ['600vp', '700vp', '800vp', '900vp', '1000vp'], + reference: BreakpointsReference.WindowSize}}) { + GridCol({span:{xs: 12, sm: 12, md: 12, lg:12, xl: 12, xxl:12}}) { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium) + } + } + }.onBreakpointChange((currentBreakpoint: string) => { + this.currentBreakpoint = currentBreakpoint + }) + } +} +``` + +**(二)栅格断点默认以窗口宽度为参照物,同时还允许开发者配置为以栅格组件本身的宽度为参照物。** + +栅格既可以用于页面整体布局的场景,也可以用于页面局部布局的场景。考虑到在实际场景中,存在应用窗口尺寸不变但是局部区域尺寸发生了变化的情况,栅格组件支持以自身宽度为参照物响应断点变化具有更大的灵活性。 + +**示例2:** + +以栅格组件宽度为参考物响应断点变化。满足窗口尺寸不变,而部分内容区需要做响应式变化的场景。 + +为了便于理解,下图中自定义预览器的设备屏幕宽度设置为650vp。示例代码中将侧边栏的变化范围控制在[100vp, 600vp],那么右侧的栅格组件宽度相对应在[550vp, 50vp]之间变化。根据代码中对栅格断点的配置,栅格组件宽度发生变化时,其断点相应的发生改变。 + +![component](figures/component.gif) + + +``` +@Entry +@Component +struct GridRowSample2 { + @State private currentBreakpoint: string = 'unknown'; + build() { + // 用户可以通过拖拽侧边栏组件中的分隔线,调整侧边栏和内容区的宽度。 + SideBarContainer(SideBarContainerType.Embed) + { + // 侧边栏,尺寸变化范围 [100vp, 600vp] + Column(){}.width('100%').backgroundColor('#19000000') + + // 内容区,尺寸变化范围 [窗口宽度550vp, 窗口宽度50vp] + GridRow({breakpoints: {value: ['100vp', '200vp', '300vp', '400vp', '500vp'], + reference: BreakpointsReference.ComponentSize}}) { + GridCol({span:{xs: 12, sm: 12, md: 12, lg:12, xl: 12, xxl:12}}) { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text(this.currentBreakpoint).fontSize(50).fontWeight(FontWeight.Medium) + } + } + }.onBreakpointChange((currentBreakpoint: string) => { + this.currentBreakpoint = currentBreakpoint; + }).width('100%') + } + // 侧边栏拖拽到最小宽度时,不自动隐藏 + .autoHide(false) + .sideBarWidth(100) + // 侧边栏的最小宽度 + .minSideBarWidth(100) + // 侧边栏的最大宽度 + .maxSideBarWidth(600) + } +} +``` + +**(三)栅格组件的断点发生变化时,会通过onBreakPointChange事件通知开发者。** + +在之前的两个例子中,已经演示了onBreakpointChange事件的用法,此处不再赘述。 + + +### 栅格组件的columns、gutter和margin + + +栅格组件columns默认为12列,gutter默认为0,同时支持开发者根据实际需要定义不同断点下的columns数量以及gutter长度。特别的,在栅格组件实际使用过程中,常常会发生多个元素占据的列数相加超过总列数而折行的场景。栅格组件还允许开发者分别定义水平方向的gutter(相邻两列之间的间距)和垂直方向的gutter(折行时相邻两行之间的间距)。 + + + 考虑到[组件通用属性](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-universal-attributes-size.md)中已经有margin和padding,栅格组件不再单独提供额外的margin属性,直接使用通用属性即可。借助margin或者padding属性,均可以控制栅格组件与父容器左右边缘的距离,但是二者也存在一些差异: +- margin区域在栅格组件的边界外,padding区域在栅格组件的边界内。 + +- 栅格组件的backgroundColor会影响padding区域,但不会影响margin区域。 + + +总的来讲,margin在组件外而padding在组件内,开发者可以根据实际需要进行选择及实现目标效果。 + + +**示例3:** + + +不同断点下,定义不同的columns和gutter。 + + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001386807405](figures/zh-cn_image_0000001386807405.jpg) | ![zh-cn_image_0000001336167540](figures/zh-cn_image_0000001336167540.jpg) | ![zh-cn_image_0000001386487457](figures/zh-cn_image_0000001386487457.jpg) | + + + +``` +@Entry +@Component +struct GridRowSample3 { + private bgColors: ResourceColor[] = [ + $r('sys.color.ohos_id_color_palette_aux1'), + $r('sys.color.ohos_id_color_palette_aux2'), + $r('sys.color.ohos_id_color_palette_aux3'), + $r('sys.color.ohos_id_color_palette_aux4'), + $r('sys.color.ohos_id_color_palette_aux5'), + $r('sys.color.ohos_id_color_palette_aux6') + ] + build() { + // 配置不同断点下columns和gutter的取值 + GridRow({columns: {sm: 4, md: 8, lg: 12}, + gutter: {x: {sm: 8, md: 16, lg: 24}, y: {sm: 8, md: 16, lg: 24}}}) { + ForEach(this.bgColors, (bgColor)=>{ + GridCol({span: {sm: 2, md: 2, lg: 2}}) { + Row().backgroundColor(bgColor).height(30) + } + }) + } + } +} +``` + + +**示例4:** + + +通过通用属性margin或者padding,均可以控制栅格组件与其父容器左右两侧的距离,但padding区域计算在栅格组件内而margin区域计算在栅格组件外。此外,借助onBreakpointChange事件,还可以改变不同断点下margin或padding值。 + + +![zh-cn_image_0000001336327452](figures/zh-cn_image_0000001336327452.png) + + + +``` +@Entry +@Component +struct GridRowSample4 { + @State private gridMargin: number = 0 + build() { + Column() { + Row().width('100%').height(30) + + // 使用padding控制栅格左右间距 + GridRow() { + GridCol({span:{xs: 12, sm: 12, md: 12, lg:12}}) { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("padding").fontSize(24).fontWeight(FontWeight.Medium) + }.backgroundColor('#19000000') + } + } + .height(50) + .borderWidth(2) + .borderColor('#F1CCB8') + .padding({left: this.gridMargin, right: this.gridMargin}) + // 借助断点变化事件配置不同断点下栅格组件的左右间距值 + .onBreakpointChange((currentBreakpoint: string) => { + if (currentBreakpoint === 'lg' || currentBreakpoint === 'md') { + this.gridMargin = 24 + } else { + this.gridMargin = 12 + } + }) + + Row().width('100%').height(30) + + // 使用margin控制栅格左右间距 + GridRow() { + GridCol({span:{xs: 12, sm: 12, md: 12, lg:12}}) { + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { + Text("margin").fontSize(24).fontWeight(FontWeight.Medium) + }.backgroundColor('#19000000') + } + } + .height(50) + .borderWidth(2) + .borderColor('#F1CCB8') + .margin({left: this.gridMargin, right: this.gridMargin}) + } + } +} +``` + + +### 栅格组件的span、offset和order + + +栅格组件(GridRow)的直接孩子节点只可以是栅格子组件(GridCol),GridCol组件支持配置span、offset和order三个参数。这三个参数的取值按照"xs -> sm -> md -> lg -> xl -> xxl"的向后方向具有继承性(不支持向前方向的继承性),例如将sm断点下span的值配置为3,不配置md断点下span的值,则md断点下span的取值也是3。 + + + | 参数名 | 类型 | 必填 | 默认值 | 说明 | +| -------- | -------- | -------- | -------- | -------- | +| span | {xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?:number} | 是 | - | 在栅格中占据的列数。span为0,意味着该元素既不参与布局计算,也不会被渲染。 | +| offset | {xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?:number} | 否 | 0 | 相对于前一个栅格子组件偏移的列数。 | +| order | {xs?: number, sm?: number, md?: number, lg?: number, xl?: number, xxl?:number} | 否 | 0 | 元素的序号,根据栅格子组件的序号,从小到大对栅格子组件做排序。 | + + +**示例5:** + + +通过span参数配置GridCol在不同断点下占据不同的列数。特别的,将md断点下和6的span配置为0,这样在md断点下3和6不会渲染和显示。 + + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001336487884](figures/zh-cn_image_0000001336487884.jpg) | ![zh-cn_image_0000001386648317](figures/zh-cn_image_0000001386648317.jpg) | ![zh-cn_image_0000001386327997](figures/zh-cn_image_0000001386327997.jpg) | + + + +``` +@Entry +@Component +struct GridRowSample5 { + private elements: Object[] = [ + {'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')}, + {'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')}, + {'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')}, + {'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')}, + {'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')}, + {'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')}, + ] + + build() { + GridRow() { + ForEach(this.elements, (item)=>{ + GridCol({span: {sm: 6, md: (item.index % 3 === 0) ? 0 : 4, lg: 3}}) { + Row() { + Text('' + item.index).fontSize(24) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(item.color).height(30) + } + }) + } + } +} +``` + + +**示例6:** + + +通过offset参数,配置GridCol相对其前一个兄弟间隔的列数。 + + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001386807873](figures/zh-cn_image_0000001386807873.jpg) | ![zh-cn_image_0000001336168020](figures/zh-cn_image_0000001336168020.jpg) | ![zh-cn_image_0000001386487913](figures/zh-cn_image_0000001386487913.jpg) | + + + +``` +@Entry +@Component +struct GridRowSample6 { + private elements: Object[] = [ + {'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')}, + {'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')}, + {'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')}, + {'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')}, + {'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')}, + {'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')}, + ] + + build() { + GridRow() { + ForEach(this.elements, (item)=>{ + GridCol({span: {sm: 6, md: 4, lg: 3}, offset: {sm: 0, md: 2, lg: 1} }) { + Row() { + Text('' + item.index).fontSize(24) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(item.color).height(30) + } + }) + } + } +} +``` + + +**示例7:** + + +通过order属性,控制GridCol的顺序。在sm和md断点下,按照至6的顺序排列显示;在lg断点下,按照6至1的顺序排列显示。 + + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001336327916](figures/zh-cn_image_0000001336327916.jpg) | ![zh-cn_image_0000001336008356](figures/zh-cn_image_0000001336008356.jpg) | ![zh-cn_image_0000001336487888](figures/zh-cn_image_0000001336487888.jpg) | + + + +``` +@Entry +@Component +struct GridRowSample7 { + private elements: Object[] = [ + {'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')}, + {'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')}, + {'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')}, + {'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')}, + {'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')}, + {'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')}, + ] + + build() { + GridRow() { + ForEach(this.elements, (item)=>{ + GridCol({span: {sm: 6, md: 4, lg: 3}, order: {lg: (6-item.index)}}) { + Row() { + Text('' + item.index).fontSize(24) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(item.color).height(30) + } + }) + } + } +} +``` + + +**示例8:** + + +仅配置sm和lg断点下span、offset和order参数的值,则md断点下这三个参数的取值与sm断点相同(按照“sm->md->lg”的向后方向继承)。 + + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001386648321](figures/zh-cn_image_0000001386648321.jpg) | ![zh-cn_image_0000001386328001](figures/zh-cn_image_0000001386328001.jpg) | ![zh-cn_image_0000001386807877](figures/zh-cn_image_0000001386807877.jpg) | + + + +``` +@Entry +@Component +struct GridRowSample8 { + private elements: Object[] = [ + {'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')}, + {'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')}, + {'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')}, + {'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')}, + {'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')}, + {'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')}, + ] + + build() { + GridRow() { + ForEach(this.elements, (item)=>{ + // 不配置md断点下三个参数的值,则其取值与sm断点相同 + GridCol({span: {sm:4, lg: 3}, offset: {sm: 2, lg: 1}, + order: {sm: (6-item.index), lg: item.index}}) { + Row() { + Text('' + item.index).fontSize(24) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(item.color).height(30) + } + }) + } + } +} +``` + + +### 栅格组件的嵌套使用 + +栅格组件可以嵌套使用以满足复杂场景的需要。 + +**示例9:** + + | sm | md | lg | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001336338670](figures/zh-cn_image_0000001336338670.jpg) | ![zh-cn_image_0000001336019094](figures/zh-cn_image_0000001336019094.jpg) | ![zh-cn_image_0000001336498646](figures/zh-cn_image_0000001336498646.jpg) | + + +``` +@Entry +@Component +struct GridRowSample9 { + private elements: Object[] = [ + {'index': 1, 'color': $r('sys.color.ohos_id_color_palette_aux1')}, + {'index': 2, 'color': $r('sys.color.ohos_id_color_palette_aux2')}, + {'index': 3, 'color': $r('sys.color.ohos_id_color_palette_aux3')}, + {'index': 4, 'color': $r('sys.color.ohos_id_color_palette_aux4')}, + {'index': 5, 'color': $r('sys.color.ohos_id_color_palette_aux5')}, + {'index': 6, 'color': $r('sys.color.ohos_id_color_palette_aux6')}, + ] + + build() { + GridRow() { + GridCol({span: {sm: 12, md: 10, lg: 8}, offset: {sm: 0, md: 1, lg: 2}}) { + GridRow() { + ForEach(this.elements, (item)=>{ + GridCol({span: {sm: 6, md: 4, lg: 3}}) { + Row() { + Text('' + item.index).fontSize(24) + } + .justifyContent(FlexAlign.Center) + .backgroundColor(item.color).height(30) + } + }) + } + .backgroundColor('#19000000') + .height('100%') + } + } + } +} +``` + + +### 总结 + +如前所述,栅格组件提供了丰富的自定义能力,功能异常灵活和强大。只需要明确栅格在不同断点下的Columns、Margin、Gutter及span等参数,即可确定最终布局,无需关心具体的设备类型及设备状态(如横竖屏)等。栅格可以节约设计团队与开发团队的沟通成本,提升整体开发效率。 + +## 相关实例 + +针对栅格断点系统开发,有以下相关实例可供参考: + +- [`Weather`:一多天气(eTS)(API9)](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-intro.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-intro.md deleted file mode 100644 index ed2ade0ec850d013a841982514a0ef45dce55d13..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-intro.md +++ /dev/null @@ -1,58 +0,0 @@ -# 概览 - - -[短信](https://gitee.com/openharmony/applications_mms/tree/master)是OpenHarmony中预置的系统应用,主要包含信息查看、发送短信、接收短信、短信送达报告、删除短信等功能。在不同类型设备上,短信应用的功能完全相同,故短信应用适合使用[部署模型A](introduction.md#部署模型)(即:不同类型的设备上安装运行相同的HAP包或HAP包组合)。 - - -本案例中,在会话详情页面利用[方舟开发框架](introduction.md#方舟开发框架)提供的“一多”能力,用一套代码同时适配默认设备和平板。 - - -## 工程结构 - -短信应用的工程结构如下图所示,当前该应用的功能较少,所以直接使用了DevEco Studio创建出的默认工程结构。具体采用何种形式的工程结构,并不影响应用的开发。但是使用推荐的工程结构,目录结构更清晰,拓展性也更好。 - -短信应用UI相关的逻辑集中在views和pages两个目录,分别存放公共组件及页面。当前短信应用主要包含如下页面: - -- 信息列表页面:首页,展示信息列表。 - -- 通知信息列表页面:将通知类信息集中在一起展示,与信息列表页面类似。 - -- 会话详情页面:展示与某联系人的所有信息往来。 - -- 报告详情页面:信息发送报告的详情页面。 - -- 设置页面:消息设置页面,如是否展示送达报告等。 - - -``` -/Mms/ - ├── doc # 资料 - ├── entry - │ └── src - │ └── main - │ ├── resources # 资源配置文件存放目录 - │ ├── config.json # 全局配置文件 - │ └── ets # ets代码目录 - │ ├── ServiceAbility # 后台常驻服务 - │ └── default # 业务代码目录 - │ ├── data # 自定义数据类型 - │ ├── model # 对接数据库 - │ ├── pages # 所有页面 - │ │ ├── conversation # 会话详情页面 - │ │ ├── conversationlist # 信息列表页面 - │ │ ├── index # 初始页面 - │ │ ├── info_msg # 通知信息列表页面 - │ │ ├── query_report # 报告详情页面 - │ │ └── settings # 设置页面 - │ ├── service # 业务逻辑 - │ ├── utils # 工具类 - │ ├── views # 自定义组件 - │ └── app.ets # 应用生命周期 - ├── signs # 签名 - └── LICENSE -``` - -短信应用在开发阶段,采用了一层工程结构。由于功能较为简单,所以并没有规划共用的feature和common目录,仅采用了一层product目录。 - -- 业务形态层(product) - 该目录采用IDE工程默认创建的entry目录,开发者可根据需要在创建Module时自行更改该目录名。不同产品形态,编译出相同的短信HAP包。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-combined.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-combined.md deleted file mode 100644 index 2cb8f256aaa36f65c7daff49514f0ef9af9edd8a..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-combined.md +++ /dev/null @@ -1,47 +0,0 @@ -# 组合成型 - - -现在会话详情页面的顶部标题栏、信息列表及底部输入栏都已经准备完毕,将这三部分组合起来即可得到完整的页面。 - - -- 通过[Flex组件](../../reference/arkui-ts/ts-container-flex.md)将三个部分组合起来,注意justifyContent: FlexAlign.SpaceBetween配置项是将Flex组件中的元素按照主轴方向均匀分配,其中第一个元素与顶部对齐,最后一个元素与底部对齐。 - -- 通过[List组件](../../reference/arkui-ts/ts-container-list.md)和[ForEach语法](../../ui/ts-rending-control-syntax-foreach.md),显示整个消息列表。 - - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001225812214](figures/zh-cn_image_0000001225812214.png) | ![zh-cn_image_0000001269812713](figures/zh-cn_image_0000001269812713.png) | - - - -```ts -@Entry - @Component - struct Conversation { - build() { - Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, - justifyContent: FlexAlign.SpaceBetween }) { - Column() { - TopArea() // 顶部标题栏 - List() { // 消息列表 - ForEach(globalMessageList, (item, index) => { - ListItem() { - MessageItem({ - isReceived: item.isReceived, - content: item.content, - time: item.time - }) - }) - } - .listDirection(Axis.Vertical) - .edgeEffect(EdgeEffect.Spring) - } - ButtomArea() // 底部输入栏 - } - .backgroundColor("#F1F3F5") - .width('100%') - .height('100%') - } - } -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-input-field.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-input-field.md deleted file mode 100644 index 3ac4c70cc293332d49f2b41f292f36eb08869317..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-input-field.md +++ /dev/null @@ -1,44 +0,0 @@ -# 底部输入栏 - - -有了顶部工具栏的开发经验,可以发现底部输入栏的结构更为简单,它同样以Flex组件作为父容器,同时包含文本输入框(请访问[文本输入组件](../../reference/arkui-ts/ts-basic-components-textarea.md)查看详细介绍)和消息发送图标两个子节点。 - - -![zh-cn_image_0000001285597989](figures/zh-cn_image_0000001285597989.jpg) - - -为了便于查看效果,我们同样给底部输入栏设置了淡蓝色的背景色。注意这里有一个特殊的地方,我们给TextArea设置了flexGrow(1)属性。flexGrow属性仅在父组件是Flex组件时生效,表示Flex容器的剩余空间分配给此属性所在的组件的比例,flexGrow(1)表示父容器的剩余空间全部分配给此组件,详见[Flex布局](../../reference/arkui-ts/ts-universal-attributes-flex-layout.md)。 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001292656257](figures/zh-cn_image_0000001292656257.png) | ![zh-cn_image_0000001246337342](figures/zh-cn_image_0000001246337342.png) | - - - -``` -@Component - struct ButtomArea { - build() { - Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) { - TextArea({ placeholder:'短信' }) - .placeholderColor("#99000000") - .caretColor("#007DFF") - .backgroundColor("#F1F3F5") - .borderRadius(20) - .height(40) - .flexGrow(1) // 将父容器的剩余空间全部分配给此组件 - - Image($r("app.media.send")) - .height(36) - .width(36) - .opacity(0.4) - .margin({ left:12 }) - } - .height(72) - .width('100%') - .padding({ left:24, right:24, bottom:8, top:8 }) - .backgroundColor('#87CEFA') // 底部输入栏背景色,仅用于开发测试 - } - } -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-message-list.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-message-list.md deleted file mode 100644 index 6659881032cba1c979809bc284a980f1f1556d56..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-message-list.md +++ /dev/null @@ -1,285 +0,0 @@ -# 信息列表 - - -观察信息列表区域,可以发现它是由一个个消息气泡组成的,另外消息气泡在默认设备和平板上的布局有差异。本小节将围绕如下两个主题介绍如何实现消息列表。 - - -- 如何实现自定义消息气泡组件。 - -- 如何在默认设备和平板上自适应布局。 - - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001224250574](figures/zh-cn_image_0000001224250574.jpg) | ![zh-cn_image_0000001225809618](figures/zh-cn_image_0000001225809618.png) | - - -## 消息气泡 - -先做一个最简单的消息气泡,通过borderRadius属性可以设置边框的圆角半径(详见[边框设置](../../reference/arkui-ts/ts-universal-attributes-border.md))。 - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001313844881](figures/zh-cn_image_0000001313844881.png) | ![zh-cn_image_0000001313724825](figures/zh-cn_image_0000001313724825.png) | - - -``` -@Component -struct MessageBubble { - private content: string = "OpenHarmony"; - - build() { - Column() { - Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { - Text(this.content) - .fontSize(16) - .lineHeight(21) - .padding({ left: 12, right: 12, top: 8, bottom: 8 }) - .backgroundColor("#C0EBDF") - .borderRadius(24) - .fontColor("#182431") - }.width('100%') - } - .margin({left: 24, right: 24 }) - .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 - } -} -``` - -注意这个简单的消息气泡,左上角(或右上角)的样式,与实际期望不符。我们先修改发送消息右上角的样式,接收消息左上角的实现与之类似。 - -[Stack组件](../../reference/arkui-ts/ts-container-stack.md)是一个堆叠容器,其子组件按照轴方向依次堆叠,后一个子组件覆盖前一个子组件。通过其alignContent接口,可以设置子组件在容器内的对齐方式,如alignContent: Alignment.TopStart代表子组件从左上角对齐。 - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001313604829](figures/zh-cn_image_0000001313604829.png) | ![zh-cn_image_0000001313523845](figures/zh-cn_image_0000001313523845.png) | - - -``` -@Component -struct MessageBubble { - private content: string = "OpenHarmony"; - private time: string = "今天 上午 10:35"; - - build() { - Column() { - Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { - Stack({ alignContent: Alignment.TopEnd }) { // 在左上角堆叠一个小色块 - Column() - .backgroundColor("#C0EBDF") - .borderRadius(4) - .width(24) - .height(24) - Text(this.content) - .fontSize(16) - .lineHeight(21) - .padding({ left: 12, right: 12, top: 8, bottom: 8 }) - .backgroundColor("#C0EBDF") - .borderRadius(24) - .fontColor("#182431") - } - }.width('100%') - } - .margin({left: 24, right: 24 }) - .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 - } -} -``` - -接下来我们在消息气泡下方加上时间显示,如下图所示,一个消息气泡自定义组件就基本完成了。 - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001266163748](figures/zh-cn_image_0000001266163748.png) | ![zh-cn_image_0000001265685020](figures/zh-cn_image_0000001265685020.png) | - - -``` -@Component -struct MessageBubble { - private content: string = "OpenHarmony"; - private time: string = "上午 10:35"; - - build() { - Column() { - Flex({ alignItems: ItemAlign.Center, justifyContent: FlexAlign.End }) { - Stack({ alignContent: Alignment.TopEnd }) { - Column() - .backgroundColor("#C0EBDF") - .borderRadius(4) - .width(24) - .height(24) - Text(this.content) - .fontSize(16) - .lineHeight(21) - .padding({ left: 12, right: 12, top: 8, bottom: 8 }) - .backgroundColor("#C0EBDF") - .borderRadius(24) - .fontColor("#182431") - } - }.width('100%') - - // 在消息气泡底部增加时间显示 - Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, - justifyContent: FlexAlign.End}) { - Text(this.time) - .textAlign(TextAlign.Start) - .fontSize(10) - .lineHeight(13) - .fontColor("#99182431") - }.width('100%').margin({ left: 12, right: 0 }) - } - .margin({left: 24, right: 24 }) - .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 - } -} -``` - -发送出的消息和接收到的消息的消息气泡结构基本一致,可以通过增加一个标志位,让两种消息共用MessageBubble这个自定义组件,代码如下所示。将这个标志位设置true,可以查看接收消息的效果。 - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001265844904](figures/zh-cn_image_0000001265844904.png) | ![zh-cn_image_0000001266004832](figures/zh-cn_image_0000001266004832.png) | - - -``` -@Component - struct MessageBubble { - private isReceived:boolean=false; // 通过标志位,判断是发送or接收场景,进而使用不同的样式 - private content:string="OpenHarmony"; - private time:string="今天 10:00"; - - build() { - Column() { - Flex({ justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End, - alignItems: ItemAlign.Center }) { - Stack({ alignContent:this.isReceived? Alignment.TopStart: Alignment.TopEnd }) { - Column() - .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") - .borderRadius(4) - .width(24) - .height(24) - Text(this.content) - .fontSize(16) - .lineHeight(21) - .padding({ left:12, right:12, top:8, bottom:8 }) - .backgroundColor(this.isReceived?"#FFFFFF":"#C0EBDF") - .borderRadius(24) - .fontColor("#182431") - } - }.width('100%') - - Flex({ alignItems: ItemAlign.Center, direction: FlexDirection.Row, - justifyContent:this.isReceived? FlexAlign.Start: FlexAlign.End }) { - Text(this.time) - .textAlign(TextAlign.Start) - .fontSize(10) - .lineHeight(13) - .fontColor("#99182431") - }.width('100%') - .margin({ left:this.isReceived?12:0, right:this.isReceived?0:12 }) - } - .margin({left:24, right:24 }) - .backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 - } - } -``` - - -## 栅格布局 - -回顾方舟开发框架一多能力,消息气泡在默认设备和平板上布局不同,可以借助栅格布局来解决。为了方便测试,我们预定义一个全局数组。 - - -``` -const globalMessageList:any[] = [ - { - 'time':'上午 10:20', - 'content':'项目介绍', - 'isReceived':false - }, - { - 'time':'上午 10:28', - 'content':'OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台,促进万物互联产业的繁荣发展。', - 'isReceived':false - },{ - 'time':'上午 10:32', - 'content':'技术架构', - 'isReceived':true - }, - { - 'time':'上午 10:35', - 'content':'OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的组件。', - 'isReceived':true - } - ]; -``` - -结合[栅格组件](../../reference/arkui-ts/ts-container-gridcontainer.md)的定义,考虑我们当前的实际场景,GridContainer的各参数设置如下。 - -- columns:取默认值(auto),即根据设备尺寸自动设置栅格中的列数。 - -- sizeType:取默认值(SizeType.Auto),即根据设备类型自动选择。 - -- gutter:栅格布局列间距,当前场景未使用该参数,设置为0即可。 - -- margin: 栅格布局两侧间距,在开发消息气泡组件时,已经设置了左右间距,故该属性也配置为0。 - -栅格中仅包含我们自定义的消息气泡组件,该组件在各类型设备上的参数配置如下,可以通过[useSizeType属性](../../reference/arkui-ts/ts-universal-attributes-grid.md)设置消息气泡在不同场景下的尺寸和偏移值。 - -| SizeType类型 | 设备宽度(vp) | 设备总列数 | 消息气泡占用的列数 | 接收场景偏移的列数 | 发送场景偏移的列数 | -| -------- | -------- | -------- | -------- | -------- | -------- | -| XS | [0, 320) | 2 | 2 | 0 | 0 | -| SM | [320, 600) | 4 | 4 | 0 | 0 | -| MD | [600, 840) | 8 | 6 | 0 | 2 | -| LG | [840, +∞) | 12 | 8 | 0 | 4 | - -| 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001313844889](figures/zh-cn_image_0000001313844889.png) | ![zh-cn_image_0000001313724829](figures/zh-cn_image_0000001313724829.png) | - - -``` -@Component - struct MessageItem { - private isReceived:boolean; - private content:string; - private time:string; - - build() { - GridContainer({gutter:0, margin:0 }) { - Flex({ justifyContent: FlexAlign.End, alignItems: ItemAlign.End }) { - MessageBubble({ - isReceived:this.isReceived, - content:this.content, - time:this.time - }) - } - .useSizeType({ - xs: { span:2, offset:0 }, - sm: { span:4, offset:0 }, - md: { span:6, offset:this.isReceived?0:2 }, - lg: { span:8, offset:this.isReceived?0:4 } - }) - }.width('100%') - } - } - - @Entry - @Component - struct Conversation { - build() { - Column() { // 验证效果 - MessageItem({ - isReceived: globalMessageList[1].isReceived, - content: globalMessageList[1].content, - time: globalMessageList[1].time - }) - MessageItem({ - isReceived: globalMessageList[3].isReceived, - content: globalMessageList[3].content, - time: globalMessageList[3].time - }) - }.backgroundColor('#87CEFA') // 消息背景色,仅用于开发和测试 - } - } -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-structure.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-structure.md deleted file mode 100644 index 832dfdc37ac90d05d09cb09c3f38105b95fceb76..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-structure.md +++ /dev/null @@ -1,23 +0,0 @@ -# 页面结构 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001270045849](figures/zh-cn_image_0000001270045849.png) | ![zh-cn_image_0000001225486054](figures/zh-cn_image_0000001225486054.png) | - - -会话详情页面在默认设备和平板上的样式如上图所示,会话详情页面可以划分为三个部分: - - - | 页面组成 | 介绍 | -| -------- | -------- | -| 顶部标题栏 | ![zh-cn_image_0000001224250350](figures/zh-cn_image_0000001224250350.jpg) | -| 信息列表 | ![zh-cn_image_0000001268490361](figures/zh-cn_image_0000001268490361.jpg) | -| 底部输入栏 | ![zh-cn_image_0000001268250529](figures/zh-cn_image_0000001268250529.jpg) | - - -接下来我们详细介绍各部分的实现。 - - -> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** -> 为了方便理解,我们对会话详情页面做了一定的精简,本小节仅介绍会话详情页面最基础的实现。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-title-bar.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-title-bar.md deleted file mode 100644 index 202e06ef54be59b97ff4b01ba8e296b7a5d507a5..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-page-title-bar.md +++ /dev/null @@ -1,128 +0,0 @@ -# 顶部标题栏 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001268450593](figures/zh-cn_image_0000001268450593.jpg) | ![zh-cn_image_0000001225486202](figures/zh-cn_image_0000001225486202.png) | - - -顶部标题栏是一个简单的行布局,包含返回图标、联系人头像、联系人姓名和号码、拨号图标、设置图标共5个元素。其中,联系人姓名和号码以列布局的形式放在一起。 - - -在默认设备和平板上,顶部标题栏的组件结构是相同的,仅联系人姓名和号码与拨号图标的间距不同。回顾方舟开发框架一多能力介绍,这个场景可以借助Blank组件使用拉伸能力。 - - - 我们先实现联系人姓名和号码,用Flex组件作为父容器,其包含两个Text子组件,分别用于存放联系人姓名和号码。Flex组件的属性设置如下: -- direction: FlexDirection.Column:子组件在Flex容器上以列的方式排布,即主轴是垂直方向。 - -- justifyContent: FlexAlign.Center:子组件在Flex容器主轴(垂直方向)上居中对齐。 - -- alignItems: ItemAlign.Start:子组件在Flex容器交叉轴(水平方向)上首部对齐。 - - -可以查看[Flex组件](../../reference/arkui-ts/ts-container-flex.md)及[Text组件](../../reference/arkui-ts/ts-basic-components-text.md)了解这两个组件各个属性的含义及详细用法。 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001246816566](figures/zh-cn_image_0000001246816566.png) | ![zh-cn_image_0000001292777537](figures/zh-cn_image_0000001292777537.png) | - - - -``` -@Component - struct TopArea { - build() { - Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, - alignItems: ItemAlign.Start}) { - Text('张三').fontSize(16).fontColor("#182431") - Text('+123 4567 8901').fontSize(14).fontColor("#66182431") - } - } - } -``` - - -接下来我们通过width属性和height属性设置四个图标的宽高(详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md)),并将它们与联系人姓名和电话以及Blank组件一起放到Flex父容器中。为了便于查看效果,对顶部标题栏设置了淡蓝色的背景色。 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001292777233](figures/zh-cn_image_0000001292777233.png) | ![zh-cn_image_0000001246497370](figures/zh-cn_image_0000001246497370.png) | - - - -``` -@Component - struct TopArea { - build() { - Flex({ alignItems: ItemAlign.Center }) { - Image($r('app.media.back')) - .width(24) - .height(24) - Image($r('app.media.contact')) - .width(40) - .height(40) - Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, - alignItems: ItemAlign.Start}) { - Text('张三').fontSize(16).fontColor("#182431") - Text('+123 4567 8901').fontSize(14).fontColor("#66182431") - } - Blank() // 拉伸能力 - Image($r("app.media.call")) - .width(24) - .height(24) - Image($r('app.media.dots')) - .width(24) - .height(24) - } - .width('100%') - .height(56) - .backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试 - } - } -``` - - -当前标题栏中子组件的布局同预期还有些差异,接下来通过margin属性,设置各个元素的左右间距(详见[尺寸设置](../../reference/arkui-ts/ts-universal-attributes-size.md))。如下图所示,最终顶部工具栏在默认设备和平板上都可以达到预期显示效果。 - - - | 默认设备 | 平板 | -| -------- | -------- | -| ![zh-cn_image_0000001293015965](figures/zh-cn_image_0000001293015965.png) | ![zh-cn_image_0000001246656958](figures/zh-cn_image_0000001246656958.png) | - - - -``` -@Component - struct TopArea { - build() { - Flex({ alignItems: ItemAlign.Center }) { - Image($r('app.media.back')) - .width(24) - .height(24) - .margin({ left:24 }) // 设置间距 - Image($r('app.media.contact')) - .width(40) - .height(40) - .margin({ left:16, right:16 }) // 设置间距 - Flex({ direction: FlexDirection.Column, justifyContent: FlexAlign.Center, - alignItems: ItemAlign.Start}) { - Text('张三').fontSize(16).fontColor("#182431") - Text('+123 4567 8901').fontSize(14).fontColor("#66182431") - } - Blank() - Image($r("app.media.call")) - .width(24) - .height(24) - Image($r('app.media.dots')) - .width(24) - .height(24) - .margin({ left:16, right:24 }) // 设置间距 - } - .width('100%') - .height(56) - .backgroundColor('#87CEFA') // 顶部标题栏背景色,仅用于开发测试 - } - } -``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-summary.md b/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-summary.md deleted file mode 100644 index fda93c94f8c271d994e00931ab86494ea871ecb1..0000000000000000000000000000000000000000 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/sms-session-summary.md +++ /dev/null @@ -1,7 +0,0 @@ -# 总结 - - -短信应用在默认设备和平板上的功能完全相同,因此选择了部署模型A。借助方舟开发框架一多能力,短信应用实现了在默认设备和平板上共用同一份代码,同时自然也共用安装包。 - - -在实际开发过程中,会话详情页面需要从底层做数据交互,同时还要支持信息选择、信息删除、信息发送状态、输入框与输入法联动等等功能,会比本小节中介绍的基础版本复杂很多。读者如果对这部分感兴趣,可以访问[短信应用开源代码仓](https://gitee.com/openharmony/applications_mms/tree/master),了解会话详情页面的详细实现。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/start-with-a-example.md b/zh-cn/application-dev/key-features/multi-device-app-dev/start-with-a-example.md new file mode 100644 index 0000000000000000000000000000000000000000..d7416c1fb2ed844a5887f2efa642a65cbc549639 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/start-with-a-example.md @@ -0,0 +1,273 @@ +# 从一个例子开始 + + +本章通过一个天气应用,介绍一多应用的整体开发过程,包括UX设计、工程管理及调试、页面开发等。 + + +## UX设计 + +本示例中的天气应用包含主页、管理城市和添加城市三个页面,其中主页中又包含菜单和更新间隔两个弹窗,基本业务逻辑如下所示。 + +![image-20220820153523548](figures/image-20220820153523548.png) + +“一多”建议从最初的设计阶段开始就拉通多设备综合考虑。考虑实际智能终端设备种类繁多,设计师无法针对每种具体设备各自出一份UX设计图。“一多”建议从设备屏幕宽度的维度,将设备划分为四大类。设计师只需要针对这四大类设备做设计,而无需关心具体的设备形态。 + + | 设备类型 | 屏幕宽度(vp) | +| -------- | -------- | +| 超小设备 | [0, 320) | +| 小设备 | [320, 520) | +| 中设备 | [520, 840) | +| 大设备 | [840, +∞) | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> - vp是virtual pixel(虚拟像素)的缩写,是OpenHarmony中常用的长度单位,详见本文[视觉基础](visual-basics.md)小节中的介绍。 +> +> - 此处基于设备屏幕宽度划分不同设备是为了读者方便理解。通常智能设备上的应用都是以全屏的形式运行,但随着移动技术的发展,当前部分智能设备支持应用以自由窗口模式运行(即用户可以通过拖拽等操作自由调整应用运行窗口的尺寸),故以应用窗口尺寸为基准进行划分更为合适,本文后续的响应式布局章节中将详细介绍相关内容。 +> +> - OpenHarmony当前仅有默认设备和平板两种设备形态,IDE在创建OpenHarmony工程时也仅可以选择默认设备和平板。随着OpenHarmony的演进,其支持的设备形态会不断丰富,本文也会定期刷新相关介绍。 + +默认设备和平板对应于小设备、中设备及大设备,本示例以这三类设备场景为例,介绍不同设备上的UX设计。天气主页在不同设备上的设计图如下所示。 + + | | 小设备 | 中设备 | 大设备 | +| -------- | -------- | -------- | -------- | +| 主页 | ![zh-cn_image_0000001334020938](figures/zh-cn_image_0000001334020938.png) | ![zh-cn_image_0000001385380457](figures/zh-cn_image_0000001385380457.jpg) | ![zh-cn_image_0000001348546856](figures/zh-cn_image_0000001348546856.jpg) | + +另外,大设备中天气主页还允许用户开启或者隐藏侧边栏。 + + | 开启侧边栏 | 隐藏侧边栏 | +| -------- | -------- | +| ![zh-cn_image_0000001334340566](figures/zh-cn_image_0000001334340566.jpg) | ![zh-cn_image_0000001385100509](figures/zh-cn_image_0000001385100509.jpg) | + +从天气应用在各设备上的UX设计图中,可以观察到如下UX的一些“规律”: + +- 在不同的屏幕宽度下,应用的整体风格基本保持一致。 + +- 在相近的屏幕宽度范围内,应用的布局基本不变;在不同的屏幕宽度范围内,应用的布局有较大差异。 + +- 应用在小屏幕下显示的元素,是大屏幕中显示元素的子集。 + - 考虑到屏幕尺寸及显示效果,大屏幕中可以显示的元素数量一定不少于小屏幕。 + - 为充分利用屏幕尺寸优势,大屏幕可以有其独有的元素或设计(如本示例中的侧边栏)。 + +如此,既在各设备上体现了UX的一致性,也在各设备上体现了UX的差异性,从而既可以保障各设备上应用界面的体验,也可以最大程度复用界面代码。 + +在本文[应用UX设计章节](ux-design.md)中,将详细介绍应用的UX设计规则。 + + +## 工程管理及调试 + +在本文[IDE使用章节](ide-using.md)中,将详细介绍一多的工程创建及管理等,本小节仅介绍最基础的工程创建及多设备预览调试。 + + +### 工程创建 + +一多应用的工程创建过程,与传统应用并无较大差异。只需在工程创建过程中,注意在“Device Type”选项中勾选所有该应用期望运行的目标设备类型,保证后续该应用可以在所有目标设备上正确安装即可。 + +![project](figures/project.png) + + +### 预览调试 + +在代码开发过程中,可以开启预览器,并打开“Multi-profile preview”开关,实时观察应用在不同设备下的表现。 + +![zh-cn_image_0000001384621049](figures/zh-cn_image_0000001384621049.jpg) + +特别的,还可以点击“+ New Profile”按钮,新增自定义预览器。 + +![previewer](figures/previewer.jpg) + + +## 页面开发 + +天气应用中涉及较多的页面和弹窗,本小节以天气主页为例,简单介绍不同设备下的页面实现思路。天气应用已经在[OpenHarmony应用示例](https://gitee.com/openharmony/applications_app_samples/tree/master/MultiDeviceAppDev/Weather)中开源,感兴趣的读者可以自行下载及了解详细代码实现。 + + 观察天气主页在不同设备上的UX设计图,可以进行如下设计: +- 将天气主页划分为9个基础区域,如: + ![home_full](figures/home_full.png) + +- 基础区域9仅在大设备上显示,基础区域1-8虽然在各设备上始终展示但其尺寸及区域内的布局基本保持不变,可以结合[自适应布局](adaptive-layout.md)能力以[自定义组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/ui/ts-component-based-component.md)的形式分别实现这9个基础区域。 + | | 小设备 | 中设备 | 大设备 | + | -------- | -------- | -------- | -------- | + | 主页 | ![Home_sm](figures/Home_sm.png) | ![Home_md_mark](figures/Home_md_mark.png) | ![Home_lg_mark](figures/Home_lg_mark.png) | + +- 基础区域1-8之间的布局在不同设备上有较大差异,可以使用响应式布局中的[栅格布局](responsive-layout.md#栅格布局)能力实现组件间的布局效果。 + +- 展开和隐藏侧边栏的功能可以通过[侧边栏组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-sidebarcontainer.md)来实现。侧边栏是大设备上独有的,借助响应式布局中的[媒体查询](responsive-layout.md#媒体查询)能力,控制仅在大设备上展示侧边栏即可。 + + +### 主页基础区域 + +天气主页中的9个基础区域介绍及实现方案如下表所示。 + + | 编号 | 简介 | 实现方案 | +| -------- | -------- | -------- | +| 1 | 标题栏 | 自适应布局拉伸能力 | +| 2 | 天气概览 | Row和Column组件,并指定其子组件按照主轴起始方向对齐或居中对齐。 | +| 3 | 每小时天气 | 自适应布局延伸能力 | +| 4 | 每日天气 | 自适应布局延伸能力 | +| 5 | 空气质量 | Canvas画布组件绘制空气质量图,并使用Row组件和Column组件控制内部元素的布局。 | +| 6 | 生活指数 | 自适应布局均分能力 | +| 7 | 日出日落 | Canvas画布组件绘制日出日落图 | +| 8 | 应用信息 | Row和Column组件,并指定其子组件居中对齐。 | +| 9 | 侧边导航栏 | 综合运用自适应布局中的拉伸能力、占比能力和延伸能力 | + +天气主页涉及的内容较多,因篇幅限制,本小节仅介绍区域3(每小时天气)的实现,读者可以自行查看开源代码,了解其它基础区域的实现。 + +延伸能力是指容器组件内的子组件,按照其在列表中的先后顺序,随容器组件尺寸变化显示或隐藏。随着可用显示区域的增加,用户可以看到的“每小时天气”信息也不断增加,故“每小时天气”可以通过延伸能力实现,其核心代码如下所示。 + + +``` +@Component +export default struct HoursWeather { + ... + build() { + // 通过列表组件实现延伸能力 + List() { + LazyForEach(this.hoursDataResource, (hoursItem) => { + ListItem() { + // 具体每个小时的天气情况 + Column() { ... } + } + }, item => `${item.key}`) + } + .height(Style.CARD_HEIGHT) + .borderRadius(Style.NORMAL_RADIUS) + .backgroundColor(Style.CARD_BACKGROUND_COLOR) + // 将列表方向设置为水平方向 + .listDirection(Axis.Horizontal) + } +} +``` + + +### 城市天气详情 + +天气主页右侧的城市天气详情由区域1-8组成,区域1(标题栏)始终固定在页面顶部,区域2-8在不同设备下的布局不同且可以随页面上下滚动。本小节介绍如何实现城市天气详情中区域2~8的布局效果。 + +设备屏幕可能无法一次性显示区域2-8的所有内容,故需要在外层增加滚动组件(即Scroll组件)以支持上下滚动。不同设备下区域2-8的相对位置一共有三套不同的布局,可以借助响应式布局中的[栅格布局](responsive-layout.md#栅格布局)实现这一效果。本示例中将栅格在不同场景下分别划分为4列、8列和12列,区域2-8在不同场景下的布局如下表所示。 + + | 小设备 | 中设备 或 大设备(侧边栏显示状态) | 大设备(侧边栏隐藏状态) | +| -------- | -------- | -------- | +| ![zh-cn_image_0000001395631821](figures/zh-cn_image_0000001395631821.png) | ![zh-cn_image_0000001345312038](figures/zh-cn_image_0000001345312038.png) | ![zh-cn_image_0000001349454550](figures/zh-cn_image_0000001349454550.png) | + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 为提升用户体验,大设备侧边栏隐藏状态下,每日天气与空气质量的相对顺序发生了改变。可以调整通过GridCol栅格子组件的order属性,实现目标效果。 + + +``` +@Component +export default struct HomeContent { + ... + build() { + // 支持滚动 + Scroll() { + GridRow({ + columns: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, + gutter: { x: Style.GRID_GUTTER, y: Style.GRID_GUTTER }, + breakpoints: { reference: BreakpointsReference.WindowSize } }) { + // 天气概览 + GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 1 }) { + IndexHeader({ headerDate: this.cityListData.header, index: this.index }) + .opacity(this.headerOpacity) + } + // 每小时天气 + GridCol({ span: { sm: 4, md: 8, lg: 8 }, order: 2 }) { + HoursWeather({ hoursData: this.cityListData.hoursData }) + } + // 每日天气 + GridCol({ span: 4, order: {sm: 3, md: 3, lg: this.showSideBar ? 3 : 4} }) { + MultidayWeather({ weekData: this.cityListData.weekData }) + } + // 空气质量 + GridCol({ span: 4, order: {sm: 4, md: 4, lg: this.showSideBar ? 4 : 3} }) { + AirQuality({ airData: this.cityListData.airData, airIndexData: this.cityListData.airIndex }) + } + // 生活指数 + GridCol({ span: 4, order: 5 }) { + LifeIndex({ lifeData: this.cityListData.suitDate }) + } + // 日出日落 + GridCol({ span: 4, order: 6 }) { + SunCanvas() + } + // 应用信息 + GridCol({ span: { sm: 4, md: 8, lg: this.showSideBar ? 8 : 12 }, order: 7 }) { + IndexEnd() + } + } + } + .width('100%') + } +} +``` + + +### 主页整体实现 + +综合考虑各设备下的效果,天气主页的根节点使用侧边栏组件: + +- 小设备和中设备既不展示侧边栏,也不提供控制侧边栏显示和隐藏的按钮。 + +- 大设备默认展示侧边栏,同时提供控制侧边栏显示和隐藏的按钮。 + +另外主页右侧的城市天气详情,支持左右滑动切换城市,可以使用Swiper组件实现目标效果。 + +- 小设备和中设备开启Swiper组件的导航点,引导用户通过左右滑动切换不同城市。 + +- 大设备中用户通过点击侧边栏中的城市列表即可高效的切换不同城市,此时需要关闭Swiper组件的导航点。 + + +``` +@Entry +@Component +struct Home { + ... + build() { + SideBarContainer(SideBarContainerType.Embed) { + // 左侧侧边栏 + SideContent({ showSideBar: $showSideBar }) + // 右侧内容区 + Flex({direction: FlexDirection.Column}) { + // 基础区域1标题栏 + IndexTitleBar({ curBp: this.curBp, showSideBar: $showSideBar }) + .height(56) + // 天气详情,通过Swiper组件实现左右滑动切换城市的效果 + Swiper() { + ForEach(this.cityListWeatherData, (item, index) => { + HomeContent({ showSideBar: this.showSideBar, cityListData: item, index: index }) + }, item => item.city) + } + // 大设备关闭导航点 + .indicator(this.curBp !== 'lg') + .width('100%') + } + } + .height('100%') + .sideBarWidth('33.3%') + // 通过状态变量,控制不同设备下侧边栏的显隐状态 + .showSideBar(this.showSideBar) + } +} +``` + + +最终,天气首页的运行效果如下图所示。 + + + | 小设备 | 中设备 | 大设备(隐藏侧边栏) | 大设备(显示侧边栏) | +| -------- | -------- | -------- | -------- | +| ![zh-cn_image_0000001344993822](figures/zh-cn_image_0000001344993822.jpg) | ![zh-cn_image_0000001345473362](figures/zh-cn_image_0000001345473362.jpg) | ![zh-cn_image_0000001400662385](figures/zh-cn_image_0000001400662385.png) | ![zh-cn_image_0000001395713305](figures/zh-cn_image_0000001395713305.jpg) | + + +## 功能开发 + +应用开发不仅包含应用页面开发,还包括应用后端功能开发以及服务器端开发等。服务器端开发不在本文的讨论范围内,本小节仅介绍多设备上应用功能开发的注意事项。 + +如前文所示,本示例的目标运行设备是小设备、中设备和大设备,对应实际的设备类型为默认设备和平板等。这些设备运行的都是标准系统,其系统能力一致,所以无需做特别考虑。但是在超小设备(对应的实际设备类型为智能穿戴设备等)上,考虑CPU、内存、硬盘等硬件限制,往往会对系统进行裁剪。如果在应用后端功能开发时调用当前系统没有的能力,就可能会引发异常。 + +通常有两种方式解决上述问题: + +- 在应用安装包中描述其需要的系统能力,保证本应用仅被分发和安装到可以满足其诉求的系统中。 + +- 在使用特定系统能力前,通过canIUse接口判断系统能力是否存在,进而执行不同的逻辑。 + +在本文的[功能开发的一多能力介绍](development-intro.md)章节中,将详细展开介绍。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/typical-layout-scenario.md b/zh-cn/application-dev/key-features/multi-device-app-dev/typical-layout-scenario.md new file mode 100644 index 0000000000000000000000000000000000000000..d86bc2324676c2a97b6c59c03bceef9b8f083ba1 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/typical-layout-scenario.md @@ -0,0 +1,845 @@ +# 典型布局场景 + + +虽然不同应用的页面千变万化,但对其进行拆分和分析,页面中的很多布局场景是相似的。本小节将介绍如何借助自适应布局、响应式布局以及常见的容器类组件,实现应用中的典型布局场景。 + + + | 布局场景 | 实现方案 | +| -------- | -------- | +| [页签栏](#页签栏) | Tab组件 + 响应式布局 | +| [运营横幅(Banner)](#运营横幅banner) | Swiper组件 + 响应式布局 | +| [网格](#网格) | Grid组件 / List组件 + 响应式布局 | +| [侧边栏](#侧边栏) | SiderBar组件 + 响应式布局 | +| [大图浏览](#大图浏览) | Image组件 | +| [操作入口](#操作入口) | Scroll组件+Row组件横向均分 | +| [顶部](#顶部) | 栅格组件 | +| [缩进布局](#缩进布局) | 栅格组件 | +| [挪移布局](#挪移布局) | 栅格组件 | +| [重复布局](#重复布局) | 栅格组件 | + + +> ![icon-note.gif](public_sys-resources/icon-note.gif) **说明:** +> 在本文[媒体查询](responsive-layout.md#媒体查询)小节中已经介绍了如何通过媒体查询监听断点变化,后续的示例中不再重复介绍此部分代码。 + + +## 页签栏 + +**布局效果** + +| sm | md | lg | +| -------- | -------- | -------- | +| 页签在底部
页签的图标和文字垂直布局
页签宽度均分
页签高度固定72vp | 页签在底部
页签的图标和文字水平布局
页签宽度均分
页签高度固定56vp | 页签在左边
页签的图标和文字垂直布局
页签宽度固定96vp
页签高度总占比‘60%’后均分 | +| ![页签布局手机](figures/页签布局手机.png) | ![页签布局折叠屏](figures/页签布局折叠屏.png) | ![页签布局matePadPro](figures/页签布局matePadPro.png) | + + +**实现方案** + +不同断点下,页签在页面中的位置及尺寸都有差异,可以结合响应式布局能力,设置不同断点下[Tab组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabs.md)的barPosition、vertical、barWidth和barHeight属性实现目标效果。 + +另外,页签栏中的文字和图片的相对位置不同,同样可以通过设置不同断点下[tabBar](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-tabcontent.md#%E5%B1%9E%E6%80%A7)对应的CustomBuilder中的布局方向,实现目标效果。 + + +**参考代码** + + +``` +import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem' + +type TabBar = { + name: string + icon: Resource + selectIcon: Resource +} + +@Entry +@Component +struct Home { + @State currentIndex: number = 0 + @State tabs: Array = [{ + name: '首页', + icon: $r('app.media.ic_music_home'), + selectIcon: $r('app.media.ic_music_home_selected') + }, { + name: '排行榜', + icon: $r('app.media.ic_music_ranking'), + selectIcon: $r('app.media.ic_music_ranking_selected') + }, { + name: '我的', + icon: $r('app.media.ic_music_me_nor'), + selectIcon: $r('app.media.ic_music_me_selected') + }] + + @Builder TabBarBuilder(index: number, tabBar: TabBar) { + Flex({ + direction: new BreakPointType({ + sm: FlexDirection.Column, + md: FlexDirection.Row, + lg: FlexDirection.Column + }).getValue(this.currentBreakpoint), + justifyContent: FlexAlign.Center, + alignItems: ItemAlign.Center + }) { + Image(this.currentIndex === index ? tabBar.selectIcon : tabBar.icon) + .size({ width: 36, height: 36 }) + Text(tabBar.name) + .fontColor(this.currentIndex === index ? '#FF1948' : '#999') + .margin(new BreakPointType({ + sm: { top: 4 }, + md: { left: 8 }, + lg: { top: 4 } }).getValue(this.currentBreakpoint)) + .fontSize(16) + } + .width('100%') + .height('100%') + } + + @StorageLink('currentBreakpoint') currentBreakpoint: string = 'md' + private breakpointSystem: BreakpointSystem = new BreakpointSystem() + + aboutToAppear() { + this.breakpointSystem.register() + } + + aboutToDisappear() { + this.breakpointSystem.unregister() + } + + build() { + Tabs({ + barPosition: new BreakPointType({ + sm: BarPosition.End, + md: BarPosition.End, + lg: BarPosition.Start + }).getValue(this.currentBreakpoint) + }) { + ForEach(this.tabs, (item, index) => { + TabContent() { + Stack() { + Text(item.name).fontSize(30) + }.width('100%').height('100%') + }.tabBar(this.TabBarBuilder(index, item)) + }) + } + .vertical(new BreakPointType({ sm: false, md: false, lg: true }).getValue(this.currentBreakpoint)) + .barWidth(new BreakPointType({ sm: '100%', md: '100%', lg: '96vp' }).getValue(this.currentBreakpoint)) + .barHeight(new BreakPointType({ sm: '72vp', md: '56vp', lg: '60%' }).getValue(this.currentBreakpoint)) + .animationDuration(0) + .onChange((index: number) => { + this.currentIndex = index + }) + } +} +``` + + +## 运营横幅(Banner) + + +**布局效果** + | sm | md | lg | +| -------- | -------- | -------- | +| 展示一个内容项 | 展示两个内容项 | 展示三个内容项 | +| ![banner1](figures/banner1.PNG) | ![banner2](figures/banner2.PNG) | ![banner3](figures/banner3.PNG) | + + +**实现方案** + +运营横幅通常使用[Swiper组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-swiper.md)实现。不同断点下,运营横幅中展示的图片数量不同。只需要结合响应式布局,配置不同断点下Swiper组件的displayCount属性,即可实现目标效果。 + +**参考代码** + + +``` +import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem' + +@Entry +@Component +export default struct Banner { + private data: Array = [ + $r('app.media.banner1'), + $r('app.media.banner2'), + $r('app.media.banner3'), + $r('app.media.banner4'), + $r('app.media.banner5'), + $r('app.media.banner6'), + ] + private breakpointSystem: BreakpointSystem = new BreakpointSystem() + @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md' + + aboutToAppear() { + this.breakpointSystem.register() + } + + aboutToDisappear() { + this.breakpointSystem.unregister() + } + + build() { + Swiper() { + ForEach(this.data, (item) => { + Image(item) + .size({ width: '100%', height: 200 }) + .borderRadius(12) + .padding(8) + }) + } + .indicator(new BreakPointType({ sm: true, md: false, lg: false }).getValue(this.currentBreakpoint)) + .displayCount(new BreakPointType({ sm: 1, md: 2, lg: 3 }).getValue(this.currentBreakpoint)) + } +} +``` + + +## 网格 + +**布局效果** + + | sm | md | lg | +| -------- | -------- | -------- | +| 展示两列 | 展示四列 | 展示六列 | +| ![多列列表手机](figures/多列列表手机.png) | ![多列列表折叠屏](figures/多列列表折叠屏.png) | ![多列列表matePadPro](figures/多列列表matePadPro.png) | + + +**实现方案** + +不同断点下,页面中图片的排布不同,此场景可以通过响应式布局能力结合[Grid组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-grid.md)实现,通过调整不同断点下的Grid组件的columnsTemplate属性即可实现目标效果。 + +另外,由于本例中各列的宽度相同,也可以通过响应式布局能力结合[List组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-list.md)实现,通过调整不同断点下的List组件的lanes属性也可实现目标效果。 + + +**参考代码** + +通过Grid组件实现 + + +``` +import { BreakpointSystem, BreakPointType } from 'common/breakpointsystem' + +type GridItemInfo = { + name: string + image: Resource +} + +@Entry +@Component +struct MultiLaneList { + private data: GridItemInfo[] = [ + { name: '歌单集合1', image: $r('app.media.1') }, + { name: '歌单集合2', image: $r('app.media.2') }, + { name: '歌单集合3', image: $r('app.media.3') }, + { name: '歌单集合4', image: $r('app.media.4') }, + { name: '歌单集合5', image: $r('app.media.5') }, + { name: '歌单集合6', image: $r('app.media.6') }, + { name: '歌单集合7', image: $r('app.media.7') }, + { name: '歌单集合8', image: $r('app.media.8') }, + { name: '歌单集合9', image: $r('app.media.9') }, + { name: '歌单集合10', image: $r('app.media.10') }, + { name: '歌单集合11', image: $r('app.media.11') }, + { name: '歌单集合12', image: $r('app.media.12') } + ] + private breakpointSystem: BreakpointSystem = new BreakpointSystem() + @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md' + + aboutToAppear() { + this.breakpointSystem.register() + } + + aboutToDisappear() { + this.breakpointSystem.unregister() + } + + build() { + Grid() { + ForEach(this.data, (item: GridItemInfo) => { + GridItem() { + Column() { + Image(item.image) + .aspectRatio(1.8) + Text(item.name) + .margin({ top: 8 }) + .fontSize(20) + }.padding(4) + } + }) + } + .columnsTemplate(new BreakPointType({ + sm: '1fr 1fr', + md: '1fr 1fr 1fr 1fr', + lg: '1fr 1fr 1fr 1fr 1fr 1fr' + }).GetValue(this.currentBreakpoint)) + } +} +``` + +通过List组件实现 + + +``` +import { BreakpointSystem, BreakPointType } from 'common/BreakpointSystem' + +type ListItemInfo = { + name: string + image: Resource +} + +@Entry +@Component +struct MultiLaneList { + private data: ListItemInfo[] = [ + { name: '歌单集合1', image: $r('app.media.1') }, + { name: '歌单集合2', image: $r('app.media.2') }, + { name: '歌单集合3', image: $r('app.media.3') }, + { name: '歌单集合4', image: $r('app.media.4') }, + { name: '歌单集合5', image: $r('app.media.5') }, + { name: '歌单集合6', image: $r('app.media.6') }, + { name: '歌单集合7', image: $r('app.media.7') }, + { name: '歌单集合8', image: $r('app.media.8') }, + { name: '歌单集合9', image: $r('app.media.9') }, + { name: '歌单集合10', image: $r('app.media.10') }, + { name: '歌单集合11', image: $r('app.media.11') }, + { name: '歌单集合12', image: $r('app.media.12') } + ] + private breakpointSystem: BreakpointSystem = new BreakpointSystem() + @StorageProp('currentBreakpoint') currentBreakpoint: string = 'md' + + aboutToAppear() { + this.breakpointSystem.register() + } + + aboutToDisappear() { + this.breakpointSystem.unregister() + } + + build() { + List() { + ForEach(this.data, (item: ListItemInfo) => { + ListItem() { + Column() { + Image(item.image) + Text(item.name) + .margin({ top: 8 }) + .fontSize(20) + }.padding(4) + } + }) + } + .lanes(new BreakPointType({ sm: 2, md: 4, lg: 6 }).getValue(this.currentBreakpoint)) + .width('100%') + } +} +``` + + +## 侧边栏 + +**布局效果** + + | sm | md | lg | +| -------- | -------- | -------- | +| 默认隐藏侧边栏,同时提供侧边栏控制按钮,用户可以通过按钮控制侧边栏显示或隐藏。 | 始终显示侧边栏,不提供控制按钮,用户无法隐藏侧边栏。 | 始终显示侧边栏,不提供控制按钮,用户无法隐藏侧边栏。 | +| ![sm](figures/sm.png) | ![md](figures/md.png) | ![lg](figures/lg.png) | + +**实现方案** + +侧边栏通常通过[SideBarContainer组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-sidebarcontainer.md)实现,结合响应式布局能力,在不同断点下为SiderBarConContainer组件的sideBarWidth、showControlButton等属性配置不同的值,即可实现目标效果。 + +**参考代码** + + +``` +@Entry +@Component +struct SideBarSample { + @StorageLink('currentBreakpoint') private currentBreakpoint: string = "md"; + private breakpointSystem: BreakpointSystem = new BreakpointSystem() + @State showSideBar: boolean = false + @State selectIndex: number = 0; + + aboutToAppear() { + this.breakpointSystem.register() + if (this.currentBreakpoint === 'sm') { + this.showSideBar = false + } else { + this.showSideBar = true + } + } + + aboutToDisappear() { + this.breakpointSystem.unregister() + } + + @Builder itemBuilder(index: number) { + Text(images[index].label) + .width('100%') + .fontSize(24) + .fontWeight(FontWeight.Bold) + .borderRadius(5) + .margin(20) + .backgroundColor('#ffffff') + .textAlign(TextAlign.Center) + .width(180) + .height(36) + .onClick(() => { + this.selectIndex = index + if (this.currentBreakpoint === 'sm') { + this.showSideBar = false + } + }) + } + + build() { + SideBarContainer(this.currentBreakpoint === 'sm' ? SideBarContainerType.Overlay : SideBarContainerType.Embed) { + Column() { + this.itemBuilder(0) + this.itemBuilder(1) + }.backgroundColor('#F1F3F5') + .justifyContent(FlexAlign.Center) + + Column() { + Image(images[this.selectIndex].imageSrc) + .objectFit(ImageFit.Contain) + .height(300) + .width(300) + } + .justifyContent(FlexAlign.Center) + .width('100%') + .height('100%') + } + .height('100%') + .sideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%') + .minSideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%') + .maxSideBarWidth(this.currentBreakpoint === 'sm' ? '100%' : '33.33%') + .showControlButton(this.currentBreakpoint === 'sm') + .autoHide(false) + .showSideBar(this.showSideBar) + .onChange((isBarShow: boolean) => { + this.showSideBar = isBarShow + }) + } +} +``` + + +## 大图浏览 + +**布局效果** + + + | sm | md | lg | +| -------- | -------- | -------- | +| 图片长宽比不变,最长边充满全屏 | 图片长宽比不变,最长边充满全屏 | 图片长宽比不变,最长边充满全屏 | +| ![大图浏览手机](figures/大图浏览手机.png) | ![大图浏览折叠屏](figures/大图浏览折叠屏.png) | ![大图浏览matePadPRo](figures/大图浏览matePadPRo.png) | + + +**实现方案** + +图片通常使用[Image组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-basic-components-image.md)展示,Image组件的objectFit属性默认为ImageFit.Cover,即保持宽高比进行缩小或者放大以使得图片两边都大于或等于显示边界。在大图浏览场景下,因屏幕与图片的宽高比可能有差异,常常会发生图片被截断的问题。此时只需将Image组件的objectFit属性设置为ImageFit.Contain,即保持宽高比进行缩小或者放大并使得图片完全显示在显示边界内,即可解决该问题。 + + +**参考代码** + + +``` +@Entry +@Component +struct BigImage { + build() { + Row() { + Image($r("app.media.image")) + .objectFit(ImageFit.Contain) + } + } +} +``` + + +## 操作入口 + +**布局效果** + + | sm | md | lg | +| -------- | -------- | -------- | +| 列表项尺寸固定,超出内容可滚动查看 | 列表项尺寸固定,剩余空间均分 | 列表项尺寸固定,剩余空间均分 | +| ![操作入口手机](figures/操作入口手机.png) | ![操作入口折叠屏](figures/操作入口折叠屏.png) | ![操作入口matePadPro](figures/操作入口matePadPro.png) | + + +**实现方案** + +Scroll(内容超出宽度时可滚动) + Row(横向均分:justifyContent(FlexAlign.SpaceAround)、 最小宽度约束:constraintSize({ minWidth: '100%' }) + + +**参考代码** + + +``` +type OperationItem = { + name: string + icon: Resource +} + +@Entry +@Component +export default struct OperationEntries { + @State listData: Array = [ + { name: '私人FM', icon: $r('app.media.self_fm') }, + { name: '歌手', icon: $r('app.media.singer') }, + { name: '歌单', icon: $r('app.media.song_list') }, + { name: '排行榜', icon: $r('app.media.rank') }, + { name: '热门', icon: $r('app.media.hot') }, + { name: '运动音乐', icon: $r('app.media.sport') }, + { name: '音乐FM', icon: $r('app.media.audio_fm') }, + { name: '福利', icon: $r('app.media.bonus') }] + + build() { + Scroll() { + Row() { + ForEach(this.listData, item => { + Column() { + Image(item.icon) + .width(48) + .aspectRatio(1) + Text(item.name) + .margin({ top: 8 }) + .fontSize(16) + } + .justifyContent(FlexAlign.Center) + .height(104) + .padding({ left: 12, right: 12 }) + }) + } + .constraintSize({ minWidth: '100%' }).justifyContent(FlexAlign.SpaceAround) + } + .width('100%') + .scrollable(ScrollDirection.Horizontal) + } +} +``` + + +## 顶部 + + +**布局效果** + + + | sm | md | lg | +| -------- | -------- | -------- | +| 标题和搜索框两行显示 | 标题和搜索框一行显示 | 标题和搜索框一行显示 | +| ![顶部布局手机](figures/顶部布局手机.png) | ![顶部布局折叠屏](figures/顶部布局折叠屏.png) | ![顶部布局matePadPro](figures/顶部布局matePadPro.png) | + + +**实现方案** + +最外层使用栅格行组件GridRow布局 + +文本标题使用栅格列组件GridCol + +搜索框使用栅格列组件GridCol + + +**参考代码** + + +``` +@Entry +@Component +export default struct Header { + @State needWrap: boolean = true + + build() { + GridRow() { + GridCol({ span: { sm: 12, md: 6, lg: 7 } }) { + Row() { + Text('推荐').fontSize(24) + Blank() + Image($r('app.media.ic_public_more')) + .width(32) + .height(32) + .objectFit(ImageFit.Contain) + .visibility(this.needWrap ? Visibility.Visible : Visibility.None) + } + .width('100%').height(40) + .alignItems(VerticalAlign.Center) + } + + GridCol({ span: { sm: 12, md: 6, lg: 5 } }) { + Flex({ direction: FlexDirection.Row, alignItems: ItemAlign.Center }) { + Search({ placeholder: '猜您喜欢: 万水千山' }) + .placeholderFont({ size: 16 }) + .margin({ top: 4, bottom: 4 }) + Image($r('app.media.audio_fm')) + .width(32) + .height(32) + .objectFit(ImageFit.Contain) + .flexShrink(0) + .margin({ left: 12 }) + Image($r('app.media.ic_public_more')) + .width(32) + .height(32) + .objectFit(ImageFit.Contain) + .flexShrink(0) + .margin({ left: 12 }) + .visibility(this.needWrap ? Visibility.None : Visibility.Visible) + } + } + }.onBreakpointChange((breakpoint: string) => { + if (breakpoint === 'sm') { + this.needWrap = true + } else { + this.needWrap = false + } + }) + .padding({ left: 12, right: 12 }) + } +} +``` + + +## 缩进布局 + + +**布局效果** + + + | sm | md | lg | +| -------- | -------- | -------- | +| 栅格总列数为4,内容占满所有列 | 栅格总列数为8,内容占中间6列。 | 栅格总列数为12,内容占中间8列。 | +| ![indent_sm](figures/indent_sm.jpg) | ![indent_md](figures/indent_md.jpg) | ![indent_lg](figures/indent_lg.jpg) | + + +**实现方案** + +借助[栅格组件](https://gitee.com/openharmony/docs/blob/master/zh-cn/application-dev/reference/arkui-ts/ts-container-gridrow.md),控制待显示内容在不同的断点下占据不同的列数,即可实现不同设备上的缩进效果。另外还可以调整不同断点下栅格组件与两侧的间距,获得更好的显示效果。 + + +**参考代码** + + +``` +@Entry +@Component +struct IndentationSample { + @State private gridMargin: number = 24 + build() { + Row() { + GridRow({columns: {sm: 4, md: 8, lg: 12}, gutter: 24}) { + GridCol({span: {sm: 4, md: 6, lg: 8}, offset: {md: 1, lg: 2}}) { + Column() { + ForEach([0, 1, 2, 4], () => { + Column() { + ItemContent() + } + }) + }.width('100%') + } + } + .margin({left: this.gridMargin, right: this.gridMargin}) + .onBreakpointChange((breakpoint: string) => { + if (breakpoint === 'lg') { + this.gridMargin = 48 + } else if (breakpoint === 'md') { + this.gridMargin = 32 + } else { + this.gridMargin = 24 + } + }) + } + .height('100%') + .alignItems((VerticalAlign.Center)) + .backgroundColor('#F1F3f5') + } +} + +@Component +struct ItemContent { + build() { + Column() { + Row() { + Row() { + } + .width(28) + .height(28) + .borderRadius(14) + .margin({ right: 15 }) + .backgroundColor('#E4E6E8') + + Row() { + } + .width('30%').height(20).borderRadius(4) + .backgroundColor('#E4E6E8') + }.width('100%').height(28) + + Row() { + } + .width('100%') + .height(68) + .borderRadius(16) + .margin({ top: 12 }) + .backgroundColor('#E4E6E8') + } + .height(128) + .borderRadius(24) + .backgroundColor('#FFFFFF') + .padding({ top: 12, bottom: 12, left: 18, right: 18 }) + .margin({ bottom: 12 }) + } +} +``` + + +## 挪移布局 + +**布局效果** + + | sm | md | lg | +| -------- | -------- | -------- | +| 图片和文字上下布局 | 图片和文字左右布局 | 图片和文字左右布局 | +| ![diversion_sm](figures/diversion_sm.jpg) | ![diversion_md](figures/diversion_md.jpg) | ![diversion_lg](figures/diversion_lg.jpg) | + + +**实现方案** + +不同断点下,栅格子元素占据的列数会随着开发者的配置发生改变。当一行中的列数超过栅格组件在该断点的总列数时,可以自动换行,即实现”上下布局”与”左右布局”之间切换的效果。 + + +**参考代码** + + +``` +@Entry +@Component +struct DiversionSample { + @State private currentBreakpoint: string = 'md' + @State private imageHeight: number = 0 + build() { + Row() { + GridRow() { + GridCol({span: {sm: 12, md: 6, lg: 6}}) { + Image($r('app.media.illustrator')) + .aspectRatio(1) + .onAreaChange((oldValue: Area, newValue: Area) => { + this.imageHeight = Number(newValue.height) + }) + .margin({left: 12, right: 12}) + } + + GridCol({span: {sm: 12, md: 6, lg: 6}}) { + Column(){ + Text($r('app.string.user_improvement')) + .textAlign(TextAlign.Center) + .fontSize(20) + .fontWeight(FontWeight.Medium) + Text($r('app.string.user_improvement_tips')) + .textAlign(TextAlign.Center) + .fontSize(14) + .fontWeight(FontWeight.Medium) + } + .margin({left: 12, right: 12}) + .justifyContent(FlexAlign.Center) + .height(this.currentBreakpoint === 'sm' ? 100 : this.imageHeight) + } + }.onBreakpointChange((breakpoint: string) => { + this.currentBreakpoint = breakpoint; + }) + } + .height('100%') + .alignItems((VerticalAlign.Center)) + .backgroundColor('#F1F3F5') + } +} +``` + + +## 重复布局 + +**布局效果** + +| sm | md | lg | +| -------- | -------- | -------- | +| 单列显示,共8个元素
可以通过上下滑动查看不同的元素 | 双列显示,共8个元素 | 双列显示,共8个元素 | +| ![repeat_sm](figures/repeat_sm.jpg) | ![repeat_md](figures/repeat_md.jpg) | ![repeat_lg](figures/repeat_lg.jpg) | + + +**实现方案** + +不同断点下,配置栅格子组件占据不同的列数,即可实现“小屏单列显示、大屏双列显示”的效果。另外,还可以通过栅格组件的onBreakpointChange事件,调整页面中显示的元素数量。 + + +**参考代码** + + +``` +@Entry +@Component +struct RepeatSample { + @State private currentBreakpoint: string = 'md' + @State private listItems: number[] = [1, 2, 3, 4, 5, 6, 7, 8] + @State private gridMargin: number = 24 + + build() { + Row() { + // 当目标区域不足以显示所有元素时,可以通过上下滑动查看不同的元素 + Scroll() { + GridRow({gutter: 24}) { + ForEach(this.listItems, () => { + // 通过配置元素在不同断点下占的列数,实现不同的布局效果 + GridCol({span: {sm: 12, md: 6, lg: 6}}) { + Column() { + RepeatItemContent() + } + } + }) + } + .margin({left: this.gridMargin, right: this.gridMargin}) + .onBreakpointChange((breakpoint: string) => { + this.currentBreakpoint = breakpoint; + if (breakpoint === 'lg') { + this.gridMargin = 48 + } else if (breakpoint === 'md') { + this.gridMargin = 32 + } else { + this.gridMargin = 24 + } + }) + }.height(348) + } + .height('100%') + .backgroundColor('#F1F3F5') + } +} + +@Component +struct RepeatItemContent { + build() { + Flex() { + Row() { + } + .width(43) + .height(43) + .borderRadius(12) + .backgroundColor('#E4E6E8') + .flexGrow(0) + + Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Start, justifyContent: FlexAlign.SpaceAround }) { + Row() { + } + .height(10) + .width('80%') + .backgroundColor('#E4E6E8') + + Row() { + } + .height(10) + .width('50%') + .backgroundColor('#E4E6E8') + } + .flexGrow(1) + .margin({ left: 13 }) + } + .padding({ top: 13, bottom: 13, left: 13, right: 37 }) + .height(69) + .backgroundColor('#FFFFFF') + .borderRadius(24) + } +} +``` diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/typical-page-layout.md b/zh-cn/application-dev/key-features/multi-device-app-dev/typical-page-layout.md new file mode 100644 index 0000000000000000000000000000000000000000..f88f11c2da51c4a21942abce5615b0652ec501d6 --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/typical-page-layout.md @@ -0,0 +1,7 @@ +# 典型页面场景 + + + +- **[应用市场首页](appgallery-home-page.md)** + +- **[音乐专辑页](music-album-page.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/ux-design.md b/zh-cn/application-dev/key-features/multi-device-app-dev/ux-design.md new file mode 100644 index 0000000000000000000000000000000000000000..1a68a93fc353c0966d40fc04aee976be4349855f --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/ux-design.md @@ -0,0 +1,21 @@ +# 应用UX设计 + + + +- **[设计原则和要点](design-principles.md)** + +- **[应用架构设计](architecture-design.md)** + +- **[界面布局](interface-layout-design.md)** + +- **[人机交互](man-machine-interaction.md)** + +- **[视觉风格](visual-style.md)** + +- **[多态控件](design-polymorphic-controls.md)** + +- **[设计自检表](design-checklist.md)** + +- **[设计交付](design-delivery.md)** + +- **[资源](design-resources.md)** \ No newline at end of file diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-basics.md b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-basics.md similarity index 75% rename from zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-basics.md rename to zh-cn/application-dev/key-features/multi-device-app-dev/visual-basics.md index 687571e931071680459078a609100432715e871a..3a6d725e5432a2520631189b190a8f567a9c86f0 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-basics.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-basics.md @@ -1,59 +1,59 @@ -# 视觉基础 - - -**虚拟像素单位:vp** - - -虚拟像素(virtual pixel)是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果。 - - -![zh-cn_image_0000001224333864](figures/zh-cn_image_0000001224333864.png) - - -相同的vp,在不同像素密度的屏幕上,对应不同px,一般称px/vp为像素密度比。像素密度比为当前设备屏幕的dpi/160。 - - -在dpi为160的OpenHarmony设备上,像素密度比为1,则1vp等于1px。 - - -以vp为尺寸标注单位,可使相同元素在不同密度的设备上具有一致的视觉体量,使用px则容易导致体量不一致的问题。 - - -**8vp网格系统** - - -基于 8vp 为网格的基本单位可以对界面上元素的大小、位置、对齐方式进行更好的规划,构建更有层次感、秩序感,以及多设备上一致的布局效果。一些更小的控件(例如图标)大小也可以对齐 4vp 的网格大小。 - - -![zh-cn_image_0000001291670681](figures/zh-cn_image_0000001291670681.png) - - -**字体像素单位:fp** - - -字体像素(font pixel) 大小默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以 scale 系数,即 1 fp = 1 vp \* scale。 - - -**视觉属性:分层参数** - - -分层参数是根据使用场景定义的视觉属性ID,通过在不同色彩主题、多种设备上配置不同的数值,实现多设备适配的效果。OpenHarmony的分层参数包含色彩、字体、圆角、间距、阴影、模糊、缩放,并提供了默认实现。设备、应用、服务均可在此基础上管理并自定义不同场景的视觉属性。 - - -![zh-cn_image_0000001251153442](figures/zh-cn_image_0000001251153442.png) - - -例如,对于不同场景的主色调定义了对应的ID与默认实现 - - -| | | | | -| -------- | -------- | -------- | -------- | -| 主色调 | 高亮色 | \#007DFF | ohos_id_color_emphasize | -| 高亮色反色 | \#006CDE | ohos_id_color_emphasize_contrary | -| 警告色 | \#FA2A2D | ohos_id_color_warning | -| 警示色 | \#FF7500 | ohos_id_color_alert | -| 通讯色 | \#E84826 | ohos_id_color_handup | -| 通讯色 | \#00CB87 | ohos_id_color_connected | - - -关于OpenHarmony默认提供的所有分层参数,详见:[资源](resource.md) +# 视觉基础 + + +**虚拟像素单位:vp** + + +虚拟像素(virtual pixel)是一台设备针对应用而言所具有的虚拟尺寸(区别于屏幕硬件本身的像素单位)。它提供了一种灵活的方式来适应不同屏幕密度的显示效果。 + + +![zh-cn_image_0000001224333864](figures/zh-cn_image_0000001224333864.png) + + +相同的vp,在不同像素密度的屏幕上,对应不同px,一般称px/vp为像素密度比。像素密度比为当前设备屏幕的dpi/160。 + + +在dpi为160的OpenHarmony设备上,像素密度比为1,则1vp等于1px。 + + +以vp为尺寸标注单位,可使相同元素在不同密度的设备上具有一致的视觉体量,使用px则容易导致体量不一致的问题。 + + +**8vp网格系统** + + +基于 8vp 为网格的基本单位可以对界面上元素的大小、位置、对齐方式进行更好的规划,构建更有层次感、秩序感,以及多设备上一致的布局效果。一些更小的控件(例如图标)大小也可以对齐 4vp 的网格大小。 + + +![8vp](figures/8vp.png) + + +**字体像素单位:fp** + + +字体像素(font pixel) 大小默认情况下与 vp 相同,即默认情况下 1 fp = 1vp。如果用户在设置中选择了更大的字体,字体的实际显示大小就会在 vp 的基础上乘以 scale 系数,即 1 fp = 1 vp \* scale。 + + +**视觉属性:分层参数** + + +分层参数是根据使用场景定义的视觉属性ID,通过在不同色彩主题、多种设备上配置不同的数值,实现多设备适配的效果。OpenHarmony的分层参数包含色彩、字体、圆角、间距、阴影、模糊、缩放,并提供了默认实现。设备、应用、服务均可在此基础上管理并自定义不同场景的视觉属性。 + + +![画板 copy](figures/画板copy.png) + + +例如,对于不同场景的主色调定义了对应的ID与默认实现 + + +| 场景 | 色值 | ID | +| -------- | -------- | -------- | +| 高亮色 | \#007DFF | ohos_id_color_emphasize | +| 高亮色反色 | #006CDE |ohos_id_color_emphasize_contrary| +| 警告色 | \#FA2A2D |ohos_id_color_warning| +| 警示色 | \#FF7500 |ohos_id_color_alert| +| 通讯色 | \#E84826 |ohos_id_color_handup| +| 通讯色 | \#00CB87 |ohos_id_color_connected| + + +关于OpenHarmony默认提供的所有分层参数,详见:[资源](design-resources.md) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-color.md b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-color.md index 7365b869130746cfb1dcd7a5a53c25ac775124cb..fd06e85f818a852366fb282384108975b7374a3e 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-color.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-color.md @@ -1,27 +1,23 @@ -# 色彩 - - -色彩能够赋予应用界面足够的生动性,并给用户提供不同设备上、不同应用间视觉感官上的连续性。同时,合理地运用色彩可以传达关键的状态信息,给予用户即时的状态反馈以及数据可视化呈现。 - - -OpenHarmony采用蓝色作为系统的默认主色调。根据人因研究,对蓝色的接受度无论是在男性还是女性群体中,比例都是最高的。而在世界地域维度,蓝色也是最受欢迎的颜色。更重要的是,对于大多数色觉障碍人士,蓝色依然可以被辨识。 - - -**色值及使用场景** - - -在色彩设计上,既保持统一的色彩语言,又根据多端不同的使用场景做了调整,带来定制化用户体验。 - - -例如,高亮色ohos_id_color_activated,在不同设备和色彩模式上会有不同具体的值: - - -| | | | | -| -------- | -------- | -------- | -------- | -| ![zh-cn_image_0000001268654109](figures/zh-cn_image_0000001268654109.png)
用于默认设备浅色风格。 | ![zh-cn_image_0000001223973992](figures/zh-cn_image_0000001223973992.png)
用于默认设备深色风格。 | ![zh-cn_image_0000001223973996](figures/zh-cn_image_0000001223973996.png)
用于智慧屏深色风格。 | ![zh-cn_image_0000001224333892](figures/zh-cn_image_0000001224333892.png)
用于智能穿戴深色风格。 | - - -OpenHarmony后续将支持深色模式、浅色模式,及不同主题切换能力。 - - -关于OpenHarmony默认提供的色彩相关分层参数,详见:[资源](resource.md) +# 色彩 + + +色彩能够赋予应用界面足够的生动性,并给用户提供不同设备上、不同应用间视觉感官上的连续性。同时,合理地运用色彩可以传达关键的状态信息,给予用户即时的状态反馈以及数据可视化呈现。 + + +OpenHarmony采用蓝色作为系统的默认主色调。根据人因研究,对蓝色的接受度无论是在男性还是女性群体中,比例都是最高的。在世界地域维度,蓝色也是最受欢迎的颜色。更重要的是,对于大多数色觉障碍人士,蓝色依然可以被辨识。 + + +## 色值及使用场景 + +在色彩设计上,既保持统一的色彩语言,又根据多端不同的使用场景做了调整,带来定制化用户体验。 + +例如,高亮色ohos_id_color_activated,在不同设备和色彩模式上会有不同具体的值: + + | | | +| -------- | -------- | +| ![zh-cn_image_0000001400554657](figures/zh-cn_image_0000001400554657.png)
用于默认设备浅色风格。 | ![zh-cn_image_0000001400874297](figures/zh-cn_image_0000001400874297.png)
用于默认设备深色风格。 | +| ![zh-cn_image_0000001350234552](figures/zh-cn_image_0000001350234552.png)
用于智慧屏深色风格。 | ![zh-cn_image_0000001400674189](figures/zh-cn_image_0000001400674189.png)
用于智能穿戴深色风格。 | + +OpenHarmony后续将支持深色模式、浅色模式,及不同主题切换能力。 + +关于OpenHarmony默认提供的色彩相关分层参数,详见:[资源](design-resources.md) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-font.md b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-font.md index 5ea0d6b88c60f670fa111d84e54a4794fbe2f184..840f536ef52efc380cc9aeeb04fb52640f341a24 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-font.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-font.md @@ -1,16 +1,13 @@ -# 字体 - - -字体直接影响界面的展示效果和用户的阅读效率。优秀的字形设计、统一的多语言字形风格、正确的字体排版,能有效地提升应用使用体验,并传递品牌连续性。 - - -多设备字号层级 - - -选择合适的字号有助于定义内容的信息层级,以及达到内容的可读性。通过研究全场景设备的显示环境、用户使用时环境的差异,OpenHarmony结合分层参数为不同设备形态提供了一套构建信息层级的字号系统。 - - -![zh-cn_image_0000001292686089](figures/zh-cn_image_0000001292686089.png) - - -关于OpenHarmony默认提供的字体相关分层参数,详见:[资源](resource.md) +# 字体 + + +字体直接影响界面的展示效果和用户的阅读效率。优秀的字形设计、统一的多语言字形风格、正确的字体排版,能有效地提升应用使用体验,并传递品牌连续性。 + + +## 多设备字号层级 + +选择合适的字号有助于定义内容的信息层级以及增强内容的可读性。通过研究全场景设备的显示环境、用户使用时环境的差异,OpenHarmony结合分层参数为不同设备形态提供了一套构建信息层级的字号系统。 + +![字体 copy 2](figures/字体copy2.png) + +关于OpenHarmony默认提供的字体相关分层参数,详见:[资源](design-resources.md) diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-icon.md b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-icon.md index 71efed52656cebd36d303105b3a350965e696af8..1647101ade0e1696ca1d95d1b26867b00b21030f 100644 --- a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-icon.md +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style-icon.md @@ -1,10 +1,10 @@ -# 图标 - - -图标是操作系统与用户界面关键的视觉元素之一。图标应当具备直接识别关键信息或语义的特质,帮助用户轻松辨别图标所代表的含义。为了保证用户在不同的设备中视觉体验的一致性,在图标的设计上应当保持应用图标的元素一致,再根据不同的设备匹配对应的图标背板以适应于各种场景。除此之外,图标在颜色的使用上应当遵循符合人因的色彩规则,满足用户阅读的舒适度以及整体界面的和谐程度。对于面状图标与线状图标的使用也应当遵循系统的设计规则,两种样式使用同一种图形结构,降低用户阅读时再次识别的成本。 - - -![zh-cn_image_0000001268334113](figures/zh-cn_image_0000001268334113.jpg) - - -关于OpenHarmony默认提供的图标库,详见[线上图标库](https://developer.harmonyos.com/cn/design/harmonyos-icon/)。 +# 图标 + + +图标是操作系统与用户界面关键的视觉元素之一。图标应当具备直接识别关键信息或语义的特质,帮助用户轻松辨别图标所代表的含义。为了保证用户在不同的设备中视觉体验的一致性,在图标的设计上应当保持应用图标的元素一致,再根据不同的设备匹配对应的图标背板以适应于各种场景。除此之外,图标在颜色的使用上应当遵循符合人因的色彩规则,满足用户阅读的舒适度以及整体界面的和谐程度。对于面状图标与线状图标的使用应当遵循系统的设计规则,两种样式使用同一种图形结构,降低用户阅读时再次识别的成本。 + + +![zh-cn_image_0000001268334113](figures/zh-cn_image_0000001268334113.jpg) + + +关于OpenHarmony默认提供的图标库,详见[线上图标库](https://developer.harmonyos.com/cn/design/harmonyos-icon/)。 diff --git a/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style.md b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style.md new file mode 100644 index 0000000000000000000000000000000000000000..64413cf7ddb2fc1089e2f3603e226eba181f1c9c --- /dev/null +++ b/zh-cn/application-dev/key-features/multi-device-app-dev/visual-style.md @@ -0,0 +1,11 @@ +# 视觉风格 + + + +- **[视觉基础](visual-basics.md)** + +- **[色彩](visual-style-color.md)** + +- **[字体](visual-style-font.md)** + +- **[图标](visual-style-icon.md)** \ No newline at end of file