本篇案例介绍如何使用ArkTS声明式语法和基础组件,实现简易待办列表。效果为点击某一事项,替换标签图片、虚化文字。
1. 案例效果截图
2. 案例运用到的知识点
2.1. 核心知识点
- Text组件:显示一段文本的组件。
- Column组件:沿垂直方向布局的容器。
- Row组件:沿水平方向布局的容器。
2.2. 其他知识点
- ArkTS 语言基础
- 自定义组件和组件生命周期
- 内置组件:Column/Text/Row/Stack/Blank/Button
- 日志管理类的编写
- 常量与资源分类的访问
- MVVM模式
3. 代码结构
├──entry/src/main/ets // ArkTS代码区
│ ├──common
│ │ └──constants
│ │ └──CommonConstants.ets // 公共常量类
│ ├──entryability
│ │ └──EntryAbility.ets // 程序入口类
│ ├──pages
│ │ └──ToDoListPage.ets // 主页面
│ ├──view
│ │ └──ToDoItem.ets // 自定义单项待办组件
│ └──viewmodel
│ └──DataModel.ets // 列表数据获取文件
└──entry/src/main/resources // 资源文件目录
4. 公共文件与资源
本案例涉及到的常量类和工具类代码如下:
- 通用常量类
// entry/src/main/ets/common/constants/CommonConstant.ets
export default class CommonConstants {
static readonly FULL_LENGTH: string = '100%'
static readonly TITLE_WIDTH: string = '80%'
static readonly LIST_DEFAULT_WIDTH: string = '93.3%'
static readonly OPACITY_DEFAULT: number = 1
static readonly OPACITY_COMPLETED: number = 0.4
static readonly BORDER_RADIUS: number = 24
static readonly FONT_WEIGHT: number = 500
static readonly COLUMN_SPACE: number = 16
static readonly TODO_DATA: Array<string> = [
"看完1000本书",
"一次无计划的旅程",
"高空跳伞",
"拿到驾照",
"献血",
"拥有自己的房子",
"创业(无论成败)",
"亲手种出食物并吃掉"
]
}
本案例涉及到的资源文件如下:
4.1. string.json
// entry/src/main/resources/base/element/string.json
{
"string": [
{
"name": "module_desc",
"value": "module description"
},
{
"name": "EntryAbility_desc",
"value": "description"
},
{
"name": "EntryAbility_label",
"value": "清单列表"
},
{
"name": "page_title",
"value": "我的清单"
}
]
}
4.2. float.json
// entry/src/main/resources/base/element/float.json
{
"float": [
{
"name": "checkbox_width",
"value": "28vp"
},
{
"name": "checkbox_margin",
"value": "20vp"
},
{
"name": "item_font_size",
"value": "20fp"
},
{
"name": "title_font_size",
"value": "28fp"
},
{
"name": "title_font_height",
"value": "33vp"
},
{
"name": "title_margin_top",
"value": "24vp"
},
{
"name": "title_margin_bottom",
"value": "12vp"
},
{
"name": "list_item_height",
"value": "64vp"
}
]
}
其他资源请到源码中获取。
5. 功能实现
5.1. 首页逻辑
// entry/src/main/ets/pages/ToDoListPage.ets
import DataModel from '../viewmodel/DataModel'
import CommonConstants from '../common/constant/CommonConstant'
import ToDoItem from '../view/ToDoItem'
@Entry
@Component
struct ToDoListPage {
private totalTasks: Array<string> = []
aboutToAppear() {
this.totalTasks = DataModel.getData()
}
build() {
Column({ space: CommonConstants.COLUMN_SPACE }) {
Text($r('app.string.page_title'))
.fontSize($r('app.float.title_font_size'))
.fontWeight(FontWeight.Bold)
.lineHeight($r('app.float.title_font_height'))
.width(CommonConstants.TITLE_WIDTH)
.margin({
top: $r('app.float.title_margin_top'),
bottom: $r('app.float.title_margin_bottom')
})
.textAlign(TextAlign.Start)
ForEach(this.totalTasks, (item: string) => {
ToDoItem({ content: item })
}, (item: string) => JSON.stringify(item))
}
.width(CommonConstants.FULL_LENGTH)
.height(CommonConstants.FULL_LENGTH)
.backgroundColor($r('app.color.page_background'))
}
}
5.2. 数据源获取
// entry/src/main/ets/viewmodel/DataModel.ets
import CommonConstants from '../common/constant/CommonConstant'
export class DataModel {
private tasks: Array<string> = CommonConstants.TODO_DATA
getData(): Array<string> {
return this.tasks
}
}
export default new DataModel()
5.3. 列表项视图
// entry/src/main/ets/view/ToDoItem.ets
import CommonConstants from '../common/constant/CommonConstant'
@Component
export default struct ToDoItem {
private content?: string
@State isComplete: boolean = false
@Builder labelIcon(icon: Resource) {
Image(icon)
.objectFit(ImageFit.Contain)
.width($r('app.float.checkbox_width'))
.height($r('app.float.checkbox_width'))
.margin($r('app.float.checkbox_margin'))
}
build() {
Row() {
if (this.isComplete) {
this.labelIcon($r('app.media.ic_ok'))
} else {
this.labelIcon($r('app.media.ic_default'))
}
Text(this.content)
.fontSize($r('app.float.item_font_size'))
.fontWeight(CommonConstants.FONT_WEIGHT)
.opacity(this.isComplete
? CommonConstants.OPACITY_COMPLETED
: CommonConstants.OPACITY_DEFAULT)
.decoration({ type: this.isComplete
? TextDecorationType.LineThrough : TextDecorationType.None })
}
.borderRadius(CommonConstants.BORDER_RADIUS)
.backgroundColor($r('app.color.start_window_background'))
.width(CommonConstants.LIST_DEFAULT_WIDTH)
.height($r('app.float.list_item_height'))
.onClick(() => {
this.isComplete = !this.isComplete
})
}
}
6. 代码与视频教程
完整案例代码与视频教程请参见:
代码:Code-05-04.zip。
视频:《我的任务清单》。