HarmonyOS Developer 方舟开发框架与基于ArkTS的声明式开发范式
方舟开发框架概述
方舟开发框架(简称:ArkUI),是一套构建HarmonyOS应用界面的UI开发框架,它提供了极简的UI语法与包括UI组件、动画机制、事件交互等在内的UI开发基础设施,以满足应用开发者的可视化界面开发需求。
基本概念
- 组件:组件是界面搭建与显示的最小单位。开发者通过多种组件的组合,构建出满足自身应用诉求的完整界面。
- 页面:page页面是方舟开发框架最小的调度分割单位。开发者可以将应用设计为多个功能页面,每个页面进行单独的文件管理,并通过页面路由API完成页面间的调度管理,以实现应用内功能的解耦。
主要特征
- UI组件:方舟开发框架内置了丰富的多态组件,包括文本、图片、按钮等基础组件,可包含一个或多个子组件的容器组件,满足开发者自定义绘图需求的绘制组件,以及提供视频播放能力的媒体组件等。其中“多态”是指组件针对不同类型设备进行了设计,提供了在不同平台上的样式适配能力。
- 布局:UI界面设计离不开布局的参与。方舟开发框架提供了多种布局方式,除了基础的线性布局、弹性布局外,也提供了相对复杂的列表、宫格、栅格布局,以及自适应多分辨率场景开发的原子布局能力。
- 动画:动画是UI界面的重要元素之一,优秀的动画设计能够极大地提升用户体验,方舟开发框架提供了丰富的动画能力,除了组件内置动画效果外,还包括属性动画、自定义转场动画以及动画API等。
- 绘制:方舟开发框架提供了多种绘制能力,以满足开发者的自定义绘图需求,支持绘制形状、颜色填充、绘制文本、变形与裁剪、嵌入图片等。
- 交互事件:方舟开发框架提供了多种交互能力,以满足应用在不同平台通过不同输入设备进行UI交互响应的需求,默认适配了触摸手势、遥控器按键输入、键鼠输入,同时提供了相应的事件回调以便开发者添加交互逻辑。
- 平台API通道:方舟开发框架提供了API扩展机制,可通过该机制对平台能力进行封装,提供风格统一的JS接口。
- 两种开发范式:方舟开发框架针对不同的应用场景以及不同技术背景的开发者提供了两种开发范式,分别是基于ArkTS的声明式开发范式(简称“声明式开发范式”)和兼容JS的类Web开发范式(简称“类Web开发范式”)。
开发范式名称 | 简介 | 适用场景 | 适用人群 |
声明式开发范式 | 采用基于TypeScript进行声明式UI语法扩展而来的ArkTS语言,从组件、动画和状态管理三个维度提供了UI绘制能力。声明式开发范式更接近自然语义的编程方式,让开发者直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。 | 复杂度较大、团队合作度较高的应用 | 移动系统应用开发人员、系统应用开发人员 |
类Web开发范式 | 采用经典的HML、CSS、JavaScript三段式开发方式,使用HML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发刷新。该开发方式更接近Web前端开发者的使用习惯,便于快速将已有的Web应用改造成方舟开发框架应用。 | 界面较简单的中小型应用和卡片 | Web前端开发人员 |
框架结构
从上图可以看出,类Web开发范式与声明式开发范式的UI后端引擎和语言运行时是共用的,其中,UI后端引擎实现了方舟开发框架的六种基本能力。声明式开发范式无需JS Framework进行页面DOM管理,渲染更新链路更为精简,占用内存更少,因此更推荐开发者选用声明式开发范式来搭建应用UI界面。
UI与Ability框架的关系
HarmonyOS提供了FA模型与Stage模型两种应用模型。下表给出了两种模型分别与方舟开发框架的两种开发范式的关系。
FA模型:
类型 | UI开发范式 | 说明 |
应用 | 类web开发范式 | UI开发语言:使用hml/css/js 业务入口:使用固定文件名app.ets(Page类型Ability)/service.ts(Service类型Ability)/data.ts(Data类型Ability) 业务逻辑语言:js/ts |
声明式开发范式 | UI开发语言:ArkTS 业务入口:使用固定文件名app.ets(Page类型Ability)/service.ts(Service类型Ability)/data.ts(Data类型Ability) 业务逻辑语言:js/ts | |
服务卡片 | 类web开发范式 | UI开发语言:卡片显示使用hml+css+json(action) 业务入口:form.ts 卡片业务逻辑语言:js/ts |
声明式开发范式 | 当前不支持 |
Stage模型:
类型 | UI开发范式 | 说明 |
应用 | 类web开发范式 | 当前不支持 |
声明式开发范式 | UI开发语言:ArkTS 业务入口:应用模型基于ohos.application.Ability/ExtensionAbility等派生 业务逻辑语言:ts | |
服务卡片 | 类web开发范式 | UI开发语言:卡片显示使用hml+css+json(action) 业务入口:从FormExtensionAbility派生 业务逻辑语言:ts |
声明式开发范式 | 当前不支持 |
基于ArkTS的声明式开发范式
概述
基于ArkTS的声明式开发范式的方舟开发框架是一套开发极简、高性能、支持跨设备的UI开发框架,支持开发者高效地构建HarmonyOS应用UI界面。
基础能力
使用基于ArkTS的声明式开发范式的方舟开发框架,采用更接近自然语义的编程方式,让开发者可以直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。开发框架不仅从组件、动画和状态管理三个维度来提供UI能力,还提供了系统能力接口以实现系统能力的极简调用。
ArkTS语言的基础知识请参考学习ArkTS语言文档;此外,请参考基于ArkTS的声明式开发范式API文档,全面地了解内置组件,更好地开发应用。
- 开箱即用的组件
框架提供丰富的系统内置组件,可以通过链式调用的方式设置系统组件的渲染效果。开发者可以组合系统组件为自定义组件,通过这种方式将页面组件化为一个个独立的UI单元,实现页面不同单元的独立创建、开发和复用,使页面具有更强的工程性。 - 丰富的动效接口
提供svg标准的绘制图形能力,同时开放了丰富的动效接口,开发者可以通过封装的物理模型或者调用动画能力接口来实现自定义动画轨迹。 - 状态与数据管理
状态数据管理作为基于ArkTS的声明式开发范式的特色,通过功能不同的装饰器给开发者提供了清晰的页面更新渲染流程和管道。状态管理包括UI组件状态和应用程序状态,两者协作可以使开发者完整地构建整个应用的数据更新和UI渲染。 - 系统能力接口
使用基于ArkTS的声明式开发范式的方舟开发框架,还封装了丰富的系统能力接口,开发者可以通过简单的接口调用,实现从UI设计到系统能力调用的极简开发。
整体架构
- 声明式UI前端
提供了UI开发范式的基础语言规范,并提供内置的UI组件、布局和动画,提供了多种状态管理机制,为应用开发者提供一系列接口支持。 - 语言运行时
选用方舟语言运行时,提供了针对UI范式语法的解析能力、跨语言调用支持的能力和TS语言高性能运行环境。 - 声明式UI后端引擎
后端引擎提供了兼容不同开发范式的UI渲染管线,提供多种基础组件、布局计算、动效、交互事件,提供了状态管理和绘制能力。 - 渲染引擎
提供了高效的绘制能力,将渲染管线收集的渲染指令,绘制到屏幕的能力。 - 平台适配层
提供了对系统平台的抽象接口,具备接入不同系统的能力,如系统渲染管线、生命周期调度等。
声明式UI开发指导
开发说明
任务 | 简介 | 相关资源 |
准备开发环境 | 了解声明式UI的工程结构。 了解资源分类与访问。 | |
学习ArkTS语言 | ArkTS是HarmonyOS优选的主力应用开发语言,当前,ArkTS在TS基础上主要扩展了声明式UI能力。 | |
开发页面 | 根据页面的使用场景,选择合适的布局。 根据页面需要实现的内容,添加系统内置组件,并修改组件样式。 更新页面内容,丰富页面展现形式。 |
|
(可选)页面多样化 | 绘图和动画。 | |
(可选)页面之间的跳转 | 使用页面路由实现多个页面之前的跳转。 | 页面路由 |
(可选)性能提升 | 避免低性能代码对应用的性能造成负面影响。 |
创建页面
请先根据页面预期效果选择布局结构创建页面,并在页面中添加基础的系统内置组件。下述示例采用了弹性布局(Flex),对页面中的Text组件进行横纵向居中布局显示。
// xxx.ets
@Entry
@Component
struct MyComponent {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('Hello')
}
.width('100%')
.height('100%')
}
}
修改组件样式
在页面中添加系统内置组件时,若不设置属性方法,则会显示其默认样式。通过更改组件的属性样式或者组件支持的通用属性样式,改变组件的UI显示。
- 通过修改Text组件的构造参数,将Text组件的显示内容修改为“Tomato”。
- 修改Text组件的fontSize属性更改组件的字体大小,将字体大小设置为26,通过fontWeight属性更改字体粗细,将其设置为500。
// xxx.ets
@Entry
@Component
struct MyComponent {
build() {
Flex({ direction: FlexDirection.Column, alignItems: ItemAlign.Center, justifyContent: FlexAlign.Center }) {
Text('Tomato')
.fontSize(26)
.fontWeight(500)
}
.width('100%')
.height('100%')
}
}
更新页面内容
在创建基本的页面之后,可根据组件的状态来更新页面内容。以下示例展示了简单的更新页面方法。
说明
更新组件的状态之前,请先初始化组件的成员变量。自定义组件的成员变量可以通过本地初始化和在构造组件时通过构造参数初始化两种方式实现,具体允许哪种方式取决于该变量所使用的装饰器。
示例:
// xxx.ets
@Entry
@Component
struct ParentComp {
@State isCountDown: boolean = true
build() {
Column() {
Text(this.isCountDown ? 'Count Down' : 'Stopwatch').fontSize(20).margin(20)
if (this.isCountDown) {
// 图片资源放在media目录下
Image($r("app.media.countdown")).width(120).height(120)
TimerComponent({ counter: 10, changePerSec: -1, showInColor: Color.Red })
} else {
// 图片资源放在media目录下
Image($r("app.media.stopwatch")).width(120).height(120)
TimerComponent({ counter: 0, changePerSec: +1, showInColor: Color.Black })
}
Button(this.isCountDown ? 'Switch to Stopwatch' : 'Switch to Count Down')
.onClick(() => {
this.isCountDown = !this.isCountDown
})
}.width('100%')
}
}
// 自定义计时器/倒计时组件
@Component
struct TimerComponent {
@State counter: number = 0
private changePerSec: number = -1
private showInColor: Color = Color.Black
private timerId: number = -1
build() {
Text(`${this.counter}sec`)
.fontColor(this.showInColor)
.fontSize(20)
.margin(20)
}
aboutToAppear() {
this.timerId = setInterval(() => {
this.counter += this.changePerSec
}, 1000)
}
aboutToDisappear() {
if (this.timerId > 0) {
clearTimeout(this.timerId)
this.timerId = -1
}
}
}
初始创建和渲染:
- 创建父组件ParentComp;
- 本地初始化ParentComp的状态变量isCountDown;
- 执行ParentComp的build函数;
- 创建Column组件;
a. 创建Text组件,设置其文本展示内容,并将Text组件实例添加到Column中;
b. 判断if条件,创建true条件下的元素;
i. 创建Image组件,并设置其图片源地址;
ii. 使用给定的构造函数创建TimerComponent;
c. 创建Button内置组件,设置相应的内容。
状态更新:
用户单击按钮时:
- ParentComp的isCountDown状态变量的值更改为false;
- 查询构造和属性方法中使用isCountDown状态变量的UI组件:Text、Button;
- 查询使用isCountDown状态变量的渲染语法:ifElse;
- Text的UI描述被重新执行并设置新的文本内容给Text组件;
- ifElse的条件被重新执行,条件从true变为false:
a. 删除true分支下的Image和TimerComponent子组件实例;
b. 执行false分支下的UI描述:
i. 创建新的Image组件并设置其图片源地址;
ii. 使用给定的构造函数创建TimeComponent子组件;
6. Button的UI描述被重新执行并设置新的图片源地址给Image组件。