前言
健康提醒列表是萌宠日记首页底部的重要功能模块,它展示宠物即将到来的驱虫、疫苗、体检等健康事项。通过ForEach 动态渲染数据列表,每个提醒项包含图标、标题、日期、倒计时等要素,用户可以一目了然地掌握宠物的健康管理状态。
本文将从萌宠日记的健康提醒列表实现出发,深入解析 ForEach 动态渲染、列表项布局、数据绑定、以及交互反馈的设计。
一、健康提醒列表整体设计
1.1 数据模型
// HomePage.ets — 健康提醒数据结构 interface HealthReminder { icon: string // 图标(Emoji) title: string // 提醒标题 date: string // 提醒日期 daysLeft: string // 倒计时文字 color: string // 图标背景色 } private healthReminders: HealthReminder[] = [ { icon: '🛡️', title: '驱虫', date: '2024.05.20', daysLeft: '还有15天', color: '#FFF3E0' } ]1.2 列表渲染
// 健康提醒区域 Column({ space: 12 }) { // 标题行 Row() { Text('健康提醒') .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor('#333333') Blank() Text('+') .fontSize(24) .fontColor('#F5A623') } .width('100%') // 列表项 ForEach(this.healthReminders, (reminder: HealthReminder) => { Row({ space: 12 }) { // 图标 Column() { Text(reminder.icon).fontSize(24) } .width(44).height(44) .backgroundColor(reminder.color) .borderRadius(12) .justifyContent(FlexAlign.Center) // 标题和日期 Column({ space: 4 }) { Text(reminder.title) .fontSize(14) .fontWeight(FontWeight.Medium) .fontColor('#333333') Text(reminder.date) .fontSize(12) .fontColor('#999999') } .alignItems(HorizontalAlign.Start) Blank() // 倒计时 Text(reminder.daysLeft) .fontSize(12) .fontColor('#F5A623') // 右箭头 Text('›') .fontSize(18) .fontColor('#CCCCCC') } .width('100%') .padding(12) .backgroundColor('#FFFFFF') .borderRadius(12) }) } .width('100%') .padding({ left: 16, right: 16, bottom: 16 })提示:健康提醒列表使用ForEach 动态渲染,数据驱动 UI。当提醒数据发生变化时(如新增、删除、更新倒计时),UI 会自动同步更新,这是 ArkTS 声明式编程的核心优势。
二、列表项布局详解
2.1 每行布局结构
┌─────────────────────────────────────────┐ │ ┌────┐ ┌──────────────┐ 还有15天 › │ │ │🛡️ │ │ 驱虫 │ │ │ │ │ │ 2024.05.20 │ │ │ └────┘ └──────────────┘ │ └─────────────────────────────────────────┘2.2 布局分解
| 位置 | 组件 | 内容 | 说明 |
|---|---|---|---|
| 左侧 | Column | 图标 Emoji | 44×44vp 圆角容器 |
| 左中 | Column | 标题 + 日期 | 垂直排列,间距 4vp |
| 右中 | Blank | 弹性占位 | 将内容推到两端 |
| 右侧 | Text | 倒计时 | 橙色文字,引人注意 |
| 最右 | Text | › | 右箭头,暗示可点击 |
三、标题行设计
3.1 标题 + 添加按钮
Row() { Text('健康提醒') .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor('#333333') Blank() Text('+') // 添加按钮 .fontSize(24) .fontColor('#F5A623') }3.2 添加按钮交互
Text('+') .fontSize(24) .fontColor('#F5A623') .onClick(() => { // 跳转到添加提醒页面 console.log('Add new reminder') })四、动态数据绑定
4.1 数据驱动 UI
// 数据变化时,UI 自动更新 @State healthReminders: HealthReminder[] = [ { icon: '🛡️', title: '驱虫', date: '2024.05.20', daysLeft: '还有15天', color: '#FFF3E0' } ] // 添加新提醒 addReminder(reminder: HealthReminder): void { this.healthReminders.push(reminder) // @State 装饰的数组变化后,UI 自动重新渲染 } // 删除提醒 removeReminder(index: number): void { this.healthReminders.splice(index, 1) } // 更新倒计时 updateDaysLeft(): void { this.healthReminders = this.healthReminders.map(item => { // 重新计算倒计时 return { ...item, daysLeft: this.calculateDaysLeft(item.date) } }) }4.2 @State 与数组变化
| 数组操作 | UI 是否更新 | 说明 |
|---|---|---|
push() | ✅ 更新 | 新增元素 |
splice() | ✅ 更新 | 删除/替换元素 |
pop() | ✅ 更新 | 移除末尾元素 |
直接赋值 | ✅ 更新 | this.arr = newArr |
修改元素属性 | ⚠️ 需解构 | 使用...展开运算符创建新对象 |
五、倒计时计算
5.1 倒计时逻辑
// 计算倒计时 calculateDaysLeft(targetDate: string): string { const today = new Date() const target = new Date(targetDate) const diffTime = target.getTime() - today.getTime() const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) if (diffDays > 0) { return `还有${diffDays}天` } else if (diffDays === 0) { return '今天' } else { return `已过期${Math.abs(diffDays)}天` } }5.2 倒计时样式
// 根据剩余天数显示不同颜色 getDaysLeftColor(daysLeft: string): string { if (daysLeft.includes('今天')) { return '#F44336' // 红色 — 紧急 } else if (daysLeft.includes('已过期')) { return '#F44336' // 红色 — 已过期 } else { return '#F5A623' // 橙色 — 正常 } }六、列表项交互
6.1 点击事件
Row({ space: 12 }) { // 列表项内容... } .width('100%') .padding(12) .backgroundColor('#FFFFFF') .borderRadius(12) .onClick(() => { // 跳转到提醒详情/编辑页 console.log('Reminder clicked:', reminder.title) })6.2 完整交互设计
| 交互元素 | 行为 | 实现 |
|---|---|---|
| 列表项 | 点击跳转详情 | onClick |
| 添加按钮 | 跳转添加页 | onClick |
| 右箭头 | 视觉提示可点击 | Text('›') |
| 倒计时 | 状态指示 | 颜色变化 |
七、ForEach 渲染优化
7.1 key 生成器
// 为 ForEach 提供 key 生成器,提高渲染效率 ForEach( this.healthReminders, (item: HealthReminder) => { ListItem() { // 列表项内容 } }, (item: HealthReminder) => item.title // key 生成器 )7.2 带 key 与不带 key 的对比
| 对比维度 | 不带 key | 带 key |
|---|---|---|
| 渲染效率 | 重新渲染所有项 | 只更新变化的项 |
| 动画过渡 | 不支持 | 支持 item 动画 |
| 数据变化 | 全部重建 | 精准更新 |
| 推荐度 | 小列表可用 | 推荐使用 |
八、列表项样式统一
8.1 列表项容器
// 列表项的统一样式 Row({ space: 12 }) { // 内容... } .width('100%') .padding(12) // 内边距 12vp .backgroundColor('#FFFFFF') // 白色背景 .borderRadius(12) // 12vp 圆角8.2 列表项间距
// 列表项之间的间距由外层 Column 的 space 控制 Column({ space: 12 }) { // 标题行 // 列表项 1 // 列表项 2(如果有) }九、空状态与加载状态
9.1 空状态
// 当没有提醒时显示空状态 if (this.healthReminders.length === 0) { Column() { Text('🎉') .fontSize(48) Text('暂无健康提醒') .fontSize(14) .fontColor('#999999') .margin({ top: 8 }) Text('点击 + 添加提醒') .fontSize(12) .fontColor('#F5A623') .margin({ top: 4 }) } .width('100%') .padding(24) .alignItems(HorizontalAlign.Center) }9.2 加载状态
@State isLoading: boolean = true aboutToAppear(): void { // 模拟加载数据 setTimeout(() => { this.isLoading = false }, 1000) } // 加载中显示 Loading if (this.isLoading) { LoadingProgress() .width(32).height(32) .color('#F5A623') }十、最佳实践
10.1 列表设计原则
有序列表 — 列表设计的 5 个原则:
- 数据驱动:使用 ForEach 动态渲染,数据变化 UI 自动更新
- 信息层级:图标 > 标题 > 日期 > 辅助信息,从左到右重要性递减
- 交互反馈:可点击的列表项提供点击反馈
- 状态指示:倒计时使用颜色区分紧急程度
- 空状态友好:列表为空时展示引导文案
10.2 萌宠日记健康提醒列表总结
| 设计要素 | 值 | 说明 |
|---|---|---|
| 布局 | Row + Column 嵌套 | 水平布局 + 垂直布局 |
| 图标容器 | 44×44vp | 圆角 12vp |
| 标题字号 | 14fp | 中等强调 |
| 日期字号 | 12fp | 辅助信息 |
| 倒计时色 | #F5A623 | 橙色引人注意 |
| 背景色 | #FFFFFF | 白色 |
| 圆角 | 12vp | 柔和 |
总结
本文从萌宠日记的健康提醒列表实现出发,深入解析了列表动态渲染和数据绑定的完整方法:
- 数据模型:HealthReminder 接口定义提醒数据结构
- 列表渲染:ForEach 动态渲染提醒列表
- 列表项布局:图标 + 标题 + 日期 + 倒计时 + 右箭头
- 标题行设计:标题 + 添加按钮
- 动态数据绑定:@State 驱动 UI 自动更新
- 倒计时计算:日期计算与颜色状态指示
- 交互反馈:点击跳转、添加按钮
- 空状态处理:无提醒时的引导展示
健康提醒列表展示了 ArkTS 中数据驱动 UI 的典型模式,理解这一模式能为构建更复杂的列表页面打下基础。
下一篇我们将深入图标与 Emoji 在 UI 中的应用,解析 Emoji 作为 UI 图标的优势和选择策略。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- ForEach 使用:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-foreach
- @State 装饰器:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/arkts-state
- Row 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-row
- Column 组件参考:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-container-column
- Blank 组件:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-blank
- 文本溢出处理:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-basic-components-text
- 列表性能优化:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides/list-optimization
- 点击效果:https://developer.huawei.com/consumer/cn/doc/harmonyos-references/ts-universal-attributes-click-effect