我们将通过以上学习的ArkTs内容来实现一个“待办”列表案例,该案例最终效果图如下:
当我们完成一条待办时,点击其中一条待办事项呈现效果如下:
以上应用界面是由一个个页面组成,可以通过ArkUI框架声明式UI进行构建,声明式UI构建页面的过程,其实是组合组件的过程,声明式UI的思想,主要体现在两个方面:
- 描述UI的呈现结果,而不关心过程
- 状态驱动视图更新
ArkUI作为HarmonyOS应用开发的UI开发框架,其使用ArkTS语言构建自定义组件,通过组合自定义组件完成页面的构建。下面我们一步步实现这个功能。
准备图片
首先我们准备案例所需要的图片。在项目ets目录下创建images目录,将“ic_default.png”和“ic_ok.png”放入该目录。两个图片分别用于一条待办未完成和完成后的状态,如下图所示。
自定义组件-ToDoListPage
我们定义“ToDoListPage”组件的主要目的是构建整个待办事项页面。ArkTS通过struct声明组件名,并通过@Component和@Entry装饰器,来构成一个自定义组件。使用@Entry和@Component装饰的自定义组件作为页面的入口,会在页面加载时首先进行渲染。
整体代码如下:
import DataModel from './DataModel'; // 从'DataModel'文件导入DataModel类
import ToDoItem from './ToDoItem'; // 从'ToDoItem'文件导入ToDoItem类
@Entry // 标记这是入口组件
@Component // 标记这是一个组件
struct ToDoListPage { // 定义一个名为ToDoListPage的结构体,代表待办列表页面
private totalTasks: Array<string> = []; // 定义一个字符串数组,用于存储总任务
aboutToAppear() { // 页面即将出现时调用的方法
this.totalTasks = DataModel.getData(); // 从DataModel获取数据并赋值给totalTasks
}
build() { // 构建UI界面的方法
Column({ space: 16 }) { // 创建一个列布局,元素之间的间隔为16
Text("待办") // 显示文本“待办”
.fontSize("28fp") // 字体大小为28fp
.fontWeight(FontWeight.Bold) // 字体加粗
.lineHeight("33vp") // 行高为33vp
.width('80%') // 宽度占父容器的80%
.margin({ // 设置边距
top: "24vp", // 顶部边距为24vp
bottom: "12vp" // 底部边距为12vp
})
.textAlign(TextAlign.Start) // 文本对齐方式为左对齐
ForEach(this.totalTasks, (item: string) => { // 遍历totalTasks数组
ToDoItem({ content: item }) // 对于每个任务项,创建一个ToDoItem组件
}, (item: string) => JSON.stringify(item)) // 使用JSON.stringify转换每个项目的键
}
.width('100%') // 列布局的宽度为100%
.height('100%') // 高度为100%
.backgroundColor("#F1F3F5") // 背景颜色设置为#F1F3F5
}
}
当整个页面加载时,默认首先调用“aboutToAppear”方法,在该方法中我们给“totalTasks ”进行加载待办事项数据,这里使用到了“DataMode类”,参考后续实现。
“build”方法中我们首先加载“Text(“待办”)”然后通过“ForEach”函数进行循环将各个待办事项进行顺序加载,这里使用到了“ToDoItem”组件用于展示每个待办项,关于该组件参考后续代码实现。
DataModel类
DataModel类实现代码如下:
export class DataModel { // 定义并导出一个名为DataModel的类
private tasks: Array<string> = [ // 定义一个私有数组tasks,用于存储字符串类型的任务
"早起晨练", // 数组第一个元素:早起晨练
"准备早餐", // 数组第二个元素:准备早餐
"阅读名著", // 数组第三个元素:阅读名著
"学习ArkTS", // 数组第四个元素:学习ArkTS
"看剧放松" // 数组第五个元素:看剧放松
];
getData(): Array<string> { // 定义一个公开方法getData,返回一个字符串类型的数组
return this.tasks; // 返回tasks数组
}
}
export default new DataModel(); // 导出DataModel类的一个新实例
自定义组件-ToDoItem
ToDoItem主要来展示每条待办事项,并且在每条待办未完成和完成展示效果不同,实现代码如下:
@Component // 标记这是一个组件
export default struct ToDoItem { // 定义并导出名为ToDoItem的结构体
private content?: string; // 定义一个私有属性content,类型为string,可选
@State isComplete: boolean = false; // 使用@State声明一个状态变量isComplete,初始值为false
@Builder labelIcon(icon: string) { // 定义一个名为labelIcon的方法,用于构建标签图标
Image(icon) // 创建一个Image组件,图标源为icon参数
.objectFit(ImageFit.Contain) // 设置图片对象填充方式为Contain
.width("28vp") // 图片宽度为28vp
.height("28vp") // 图片高度为28vp
.margin("20vp") // 设置边距为20vp
}
build() { // 构建UI界面的方法
Row() { // 创建一个行布局
if (this.isComplete) { // 如果任务已完成
this.labelIcon("images/ic_ok.png"); // 显示完成的图标
} else { // 否则
this.labelIcon("images/ic_default.png"); // 显示默认图标
}
Text(this.content) // 显示文本内容
.fontSize("20fp") // 字体大小为20fp
.fontWeight(500) // 字体粗细为500
.opacity(this.isComplete ? 0.4 : 1) // 根据是否完成调整透明度
.decoration({ type: this.isComplete ? TextDecorationType.LineThrough : TextDecorationType.None }) // 完成时添加删除线
}
.borderRadius(24) // 设置边框圆角为24
.backgroundColor("#FFFFFF") // 背景颜色为白色
.width('93.3%') // 宽度为93.3%
.height("64vp") // 高度为64vp
.onClick(() => { // 设置点击事件
this.isComplete = !this.isComplete; // 点击时切换isComplete的状态
})
}
}
以上代码注意如下几点:
- 实际开发中由于交互,页面的内容可能需要产生变化,以每一个ToDoItem为例,其在完成时的状态与未完成时的展示效果是不一样的。声明式UI的特点就是UI是随数据更改而自动刷新的,我们这里定义了一个类型为boolean的变量isComplete,其被@State装饰后,框架内建立了数据和视图之间的绑定,其值的改变影响UI的显示。
- 用圆圈和对勾这样两个图片,分别来表示该项是否完成,这部分涉及到内容的切换,需要使用条件渲染if / else语法来进行组件的显示与消失,当判断条件为真时,组件为已完成的状态,反之则为未完成。
- 由于两个Image的实现具有大量重复代码,ArkTS提供了@Builder装饰器,来修饰一个函数,快速生成布局内容,从而可以避免重复的UI描述内容。这里使用@Bulider声明了一个labelIcon的函数,参数为url,对应要传给Image的图片路径。使用时只需要使用this关键字访问@Builder装饰的函数名,即可快速创建布局。
- 为了让待办项带给用户的体验更符合已完成的效果,给内容的字体也增加了相应的样式变化,这里使用了三目运算符来根据状态变化修改其透明度和文字样式,如opacity是控制透明度,decoration是文字是否有划线。通过isComplete的值来控制其变化。
- 为了实现与用户交互的效果,在组件上添加了onClick点击事件,当用户点击该待办项时,数据isComplete的更改就能够触发UI的更新。