ArkUI开发框架
ArkUI的演变
HarmonyOS应用开发的早期出现过两种UI框架
。
基于Java的
UI框架
。基于
eTS
(增强的TypeScript)的UI框架
。
三种开发范式
。
基于Java的
面向对象开发范式
。基于JavaScript的
类Web开发范式
。基于
eTS
的声明式开发范式
。
两种开发模型
。
Stage模型
。FA模型
。
从API 9
以后,就只有ArkTS开发范式
了。
从API 10
以后,就只有Stage模型
了。
演化至今,就逐渐变成了基于Stage模型
的ArkTS的声明式开发范式
了,也就是现在的ArkUI(或者看这里)。
声明式开发范式
ArkTS在TypeScript的基础上,扩展了声明式UI
和状态管理
等能力,让工程师以更简洁、更自然的方式开发高性能应用。

声明式语法
一个页面对应一个
.ets
文件,一个.ets
文件中可以有若干个组件。组件使用
struct
关键字(类似于Go中的结构体),并通过生成器函数build()
构建内容。组件内也可以包含其他组件,这些组件可以是系统内置组件或自定义的组件。一个页面必须有且只有一个
入口组件
,这个入口组件
由@Entry
装饰器修饰。
典型的页面文件代码如下。
// 入口装饰器
@Entry
// 组件装饰器
@Component
struct Index {
// 属性装饰器
@State message: string = 'lixingyun';
// 生成器函数
build() {
RelativeContainer() {
// 创建文本组件
Text(this.message)......
// 创建自定义组件
Ohter();
}
}
}
// 自定义组件
@Component
struct Ohter {
@State message: string = 'wanglin';
build() {
// 构建布局和组件
......
}
}
在基于ArkTS的应用开发中,HarmonyOS预定义很多内置的装饰器,例如,@Entry
、@Component
、@State
等,这些装饰器用于装饰类、结构、方法和属性等。
在build()
中构建的组件是一颗树型结构。它包括两类组件:容器组件
和普通组件
。

这种容器组件
也被称为布局
。
不管是容器组件
还是普通组件
,都可以通过.
操作符实现各种属性的链式调用。
......
Text(this.message)
.id('HelloWorld')
.fontSize(50)
.fontWeight(FontWeight.Bold)
......
或者给它们设置需要监听的事件。
......
Button("OK")
.onClick(() => {
// 处理代码
});
......
需要注意的是,build()
是用来构造UI界面
的,因此在它里面不能直接定义变量或调用函数。
@Entry
@Component
struct Index {
// 在这里自定义函数
myfunc() {
return "OK";
}
build() {
// 错误,这里不能自定义变量
let name: string = "lixingyun";
// 错误,这里不能直接调用
RelativeContainer() {
// 可以在这里调用
Text(myfunc())......
}
}
}
资源的引用
一个ArkUI项目最核心的部分就是两块:源码
和资源文件
。
所有的源代码都在
${MODULE_NANE}/src/main/ets
中,可以在其中创建Ability
、Extension Ability
、Widget
、Intent
和Page
等若干种组件,关于组件的内容在后续会有说明。所有的资源文件都在
${MODULE_NAME}/src/main/resources
中,对资源的引用目前只有两种方式。$r(value: string, ...params: any[]): Resource
:引用非原始资源。$rawfile(value: string): Resource
:引用原始资源。
引用非原始资源的基本格式为
$r('app.type.name')
。app
:代表引用resources
目录中已定义的资源,这是目前的固定写法。type
:代表引用的资源类型或存放位置。type
可以是string
、profile
、media
、color
等具体的资源类型。name
:代表引用的资源名称,由开发者定义。例如,如果开发者新建了一个string
资源,并且JSON的key
为message
,value
为the file size is %s.
,那么$r('app.string.message', '10MB')
显示的值将会是the file size is 10MB.
。
引用原始资源的基本格式为
$rawfile('filename')
。例如,在rawfile
目录下有一个images
目录,其中有一张图片名为logo.png
,那么代码可以这样引用:$rawfile('images/logo.png')
。除了代码中的资源文件,工程师还可以引用HarmonyOS预定义的系统资源,引用系统资源的固定格式为
$r('sys.type.resource_id')
,例如,$r('sys.color.ohos_id_color_emphasize')
。如果想在资源文件中引用资源,可以使用
$type:name
的方式。例如,"icon":"$media:icon"
。
组件化装饰器
@Component
由@Component
装饰的struct
结构体具备组件化的能力,这种组件也叫自定义组件。
下面是一个典型的自定义组件。
@Component
struct MyComponent {
build() {
RelativeContainer() {
Text("OK")
.fontColor(Color.Red)
}.alignItems(HorizontalAlign.Center)
}
}
使用自定义的组件。
@Component
struct OtherComponent {
build() {
RelativeContainer() {
// 调用自定义组件
MyComponent();
Text("OK")
.fontColor(Color.Red)
// 再次调用自定义组件
MyComponent();
}
}
}
@Builder
由@Builder
装饰器装饰的方法用于自定义组件内的UI
,且只有被@Builder
装饰的方法才能在build()
中调用。
@Entry
@Component
struct Index {
mySize : number = 30;
// Builder装饰器
@Builder
// 可以在build中被调用
SquareText(label: string) {
Text(label)
.width(this.mySize)
.height(this.mySize)
}
build() {
RelativeContainer() {
// 只有被Builder装饰的方法才能在build()中调用
this.SquareText("一个文本");
this.SquareText("另一个文本");
}
.width(2 * this.mySize)
.height(2 * this.mySize)
}
}
@Extend
通过@Extend
装饰器可以扩展内置组件,也就是可以将新的属性函数添加到内置组件上,实现快速、高效地复用组件的自定义样式。
@Entry
@Component
struct Test {
build() {
RelativeContainer() {
Text("您好")
// 调用扩展的功能
.myStyle(16)
}
}
}
// 扩展Text组件
@Extend(Text)
function myStyle(fontSize: number) {
.fontColor(Color.Red)
.fontSize(fontSize)
.fontStyle(FontStyle.Italic)
}
@Style
@Style
装饰器可以将新的属性添加到基本组件上,它的作用类似于@Extend
,但不是扩展而是添加属性。
// 通过@Styles装饰
@Styles function outerStyle() {
.backgroundColor(Color.Green)
}
@Entry
@Component
struct Test {
// 在组件内定义可以省略function关键字
@Styles innerStyle() {
.backgroundColor(Color.Blue)
}
build() {
RelativeContainer() {
Text("您好")
// 外面的样式
.outerStyle()
.width(100)
.height(100)
.fontSize(30);
Text("我的")
// 内部的样式
.innerStyle()
.width(100)
.height(100)
.fontSize(30);
}
}
}
组件渲染
所谓组件渲染
,就是控制组件的功能、视觉效果,以及何时呈现出这些效果。
控制渲染的方式有两种:条件渲染
和循环渲染
。
条件渲染
是指在创建组件时,根据条件执行渲染。
@Entry
@Component
struct Condition {
count: number = 100
build() {
// 容器组件
RelativeContainer() {
if (this.count < 0) {
Text('count为负数');
} else if (this.count == 0) {
Text('count == 0');
} else {
if (this.count % 2 == 0) {
Text('偶数').fontSize(22);
Divider().height(1);
} else {
Text('奇数').fontSize(22);
Divider().height(1);
}
}
}
// 错误,没有在组件容器内
if (this.count > 100) {
Text('error');
}
}
}
循环渲染
当不知道有多少组件需要渲染时,可以使用循环渲染
。
@Entry
@Component
struct Cycle {
@State arr: string[] = ['lixingyun', 'wanglin', 'xiaoyan'];
build() {
RelativeContainer() {
// 使用ForEach进行循环
ForEach(
// 参数1:数组
this.arr,
// 参数2:迭代器函数
(item: string, index: number) => {
RelativeContainer() {
Text(`下标: ${index}`);
Text(`姓名:${item}`);
}
},
// 参数3:迭代器函数
(item: string, index: number) => {
return index + item;
}
)
}
}
}
需要注意的是,不管条件渲染
还是循环渲染
,都要在容器组件(例如,build()
)内使用。
感谢支持
更多内容,请移步《超级个体》。