# 鸿蒙 HarmonyOS 应用开发实战(第33期)|喝水提醒(Water Reminder)— 可视化水杯与进度动画
一、应用概述
喝水提醒(Water Reminder) 是一款健康辅助类应用,帮助用户记录每日饮水量,并以可视化水杯的形式直观展示饮水进度。用户每点击一次「喝一杯」按钮,水杯中的水位就会上升一格,同时显示累计饮水量(毫升)和鼓励性文字提示。
从健康角度看,每日饮用 8 杯水(约 2000ml)是广为流传的健康建议。该应用以此为目标,通过视觉反馈和正向鼓励两个心理机制,激励用户达成每日饮水目标。从技术角度看,这是一个展示 Stack 层叠中动态高度变化、条件文字渲染和响应式布局的绝佳案例。
二、技术架构与组件树
2.1 整体架构
@Entry @Component struct index33
├── Column (根容器)
│ ├── Row (顶部导航栏)
│ └── Column (主内容区, 居中)
│ ├── Text ("目标: 8 杯")
│ ├── Stack (水杯可视化)
│ │ ├── Column (水杯容器, 180×200, 圆角边框)
│ │ │ └── Column (水位填充, 动态高度)
│ │ └── Column (水杯文字叠加层)
│ │ ├── Text ("🥤")
│ │ └── Text ("{count}/{target}")
│ ├── Text ("{totalMl}ml / {target*glassSize}ml")
│ ├── Text (鼓励语, 条件变化)
│ ├── Button ("🥤 喝一杯")
│ └── Row (辅助按钮)
│ ├── Button ("重置")
│ └── Button ("目标+")
2.2 状态变量设计
@State count: number = 0; // 已饮杯数
@State target: number = 8; // 日目标杯数
@State glassSize: number = 200; // 每杯毫升数
三个 @State 变量构成了应用的全部状态。其中 glassSize 被标记为 @State,虽然当前未通过 UI 修改它,但保留为状态变量意味着未来可以轻松添加用户自定义杯量功能。
三、核心代码深度解析
3.1 喝水逻辑与边界保护
addWater() {
if (this.count < this.target) {
this.count++;
}
}
addWater() 方法包含明确的边界检查:只有当前杯数小于目标杯数时才递增。这防止了用户过度点击导致进度超过 100% 的异常情况。当 count === target 时,点击按钮不再产生任何效果——这是一种"软锁止"设计,比禁用按钮更温和,用户仍然可以感受到点击反馈。
3.2 计算属性:进度、水量与鼓励语
get progress(): number {
return (this.count / this.target) * 100;
}
get totalMl(): number {
return this.count * this.glassSize;
}
get encouragement(): string {
if (this.count >= this.target) return '🎉 达标了!很棒!';
if (this.count >= this.target * 0.75) return '💪 快达标了!';
if (this.count >= this.target * 0.5) return '👍 继续加油!';
if (this.count >= this.target * 0.25) return '💧 多喝点水';
return '🚰 记得喝水';
}
三个计算属性将原始数据(count、target)转化为用户友好的显示信息:
- progress:以百分比形式返回进度值,可用于替代传统的环形进度条
- totalMl:根据杯数和杯量计算总毫升数
- encouragement:基于不同进度区间返回不同的鼓励文字,配合对应的 emoji 表情
鼓励语的区间设计合理,在 0%、25%、50%、75%、100% 五个关键节点切换文字,避免了过于频繁的变化,也让用户在每个进步阶段都能获得正向反馈。
3.3 水杯可视化——Stack 层叠的核心
Stack() {
// 水杯背景和动态水位
Column() {
Text('').width(160)
.height(this.count > 0 ? 160 * (this.count / this.target) : 0)
.backgroundColor('#4FC3F7')
.borderRadius({ bottomLeft: 20, bottomRight: 20 })
.alignSelf(ItemAlign.Center)
}
.width(180).height(200).backgroundColor('#E1F5FE')
.borderRadius(20).justifyContent(FlexAlign.End)
.border({ width: 3, color: '#81D4FA' })
// 水杯上的文字叠加
Column() {
Text('🥤').fontSize(24)
Text(`${this.count}/${this.target}`).fontSize(16)
.fontWeight(FontWeight.Bold).fontColor('#0277BD')
}
.width('100%').height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
}
水杯渲染的核心逻辑分为两层:
第一层(杯体 + 水位):
外层 Column 代表整个水杯(180×200),使用 #E1F5FE(极浅蓝色)作为空杯颜色,borderRadius(20) 创建圆角杯体,border 添加 3px 的边框模拟玻璃质感。
内层 Column 代表水位,它的 height 根据 count/target 比例动态计算:160 * (this.count / this.target)。当 count = 0 时,高度为 0——水杯看起来是空的。
这里有一个重要的布局细节:外层 Column 设置了 justifyContent(FlexAlign.End),这意味着内层水位 Column 会从底部开始排列。结合 alignSelf(ItemAlign.Center) 让水位水平居中,水的填充效果就是从杯底逐渐上升到杯顶——完美模拟了真实倒水的视觉效果。
borderRadius({ bottomLeft: 20, bottomRight: 20 }) 为水位底部添加圆角,与水杯的底部圆角匹配。水位顶部是平的,这与真实透明玻璃杯中水的视觉效果一致。
第二层(文字叠加):
第二个 Column 使用 position 叠加在水杯之上(Stack 的特性),显示 🥤 表情和 count/target 计数。justifyContent(Center) 和 alignItems(Center) 确保文字在杯体中央显示。
3.4 激励按钮与辅助操作
Button('🥤 喝一杯').width(200).height(56).borderRadius(28)
.backgroundColor('#4FC3F7').fontSize(22).margin({ top: 12 })
.onClick(() => this.addWater())
Row({ space: 8 }) {
Button('重置').width(90).height(40).borderRadius(20)
.backgroundColor('#9E9E9E')
.onClick(() => { this.count = 0 })
Button('目标+').width(90).height(40).borderRadius(20)
.backgroundColor('#FF9800')
.onClick(() => { this.target++ })
}.margin({ top: 8 })
三个按钮的设计体现了清晰的信息层级:
- 主按钮「🥤 喝一杯」:最大的尺寸(200×56),最醒目的颜色(蓝色系),是用户最频繁的操作
- 次按钮「重置」:中等大小,灰色,用于重置杯数
- 次按钮「目标+」:橙色,用于增加每日目标
「目标+」按钮允许用户灵活调整目标——如果某天想多喝水,可以增加目标杯数。但需要注意的是,当前版本没有「目标-」按钮,这可以作为一个改进点。
四、HarmonyOS 特性分析
4.1 动态高度的响应式渲染
本例最值得关注的技术点是基于 @State 的动态高度变化。当 count 递增时:
.height(this.count > 0 ? 160 * (this.count / this.target) : 0)
ArkTS 的响应式系统会自动重新计算高度值并重新渲染。这种"数据驱动高度"的模式适用于:
- 进度条/进度环
- 可伸缩面板
- 加载动画
- 数据可视化的柱状图
4.2 borderRadius 的精细控制
.borderRadius({ bottomLeft: 20, bottomRight: 20 })
ArkTS 的 borderRadius 支持对象参数,可以对四个角分别设置圆角值。这是 CSS 中 border-radius 的增强版本,比传统的四值简写更直观。
4.3 语义化颜色系统
应用使用了统一的蓝色系配色:
- 背景:#E1F5FE(极浅蓝)
- 水位:#4FC3F7(中蓝,与主按钮一致)
- 边框:#81D4FA(浅蓝)
- 文字:#0277BD(深蓝)
这种单色系设计让视觉风格高度统一,用户看到蓝色系就能联想到"水"的主题。在 HarmonyOS 中,颜色值支持六位十六进制(#RRGGBB)或八位(#AARRGGBB)格式。
五、UI/UX 设计与最佳实践
5.1 视觉反馈的心理学应用
应用的核心理念是通过即时视觉反馈激励用户行为:
- 水位上升的满足感:每次点击,蓝色水位都会增高,这种可视化的进步给人成就感
- 计数实时更新:水杯中央的
count/target数字实时变化 - 鼓励语的阶段性变化:从「记得喝水」到「达标了!很棒!」,五种文字对应五个进步阶段
5.2 交互反馈的细节
- 按钮溢出保护:当达到目标后,点击主按钮无效而不是报错
- 温和的视觉风格:圆角按钮、柔和的蓝色系、大号字体,给人友好的感觉
- 重置安全:重置仅清空杯数(count),不影响目标(target)和杯量(glassSize),避免用户误操作导致所有设置丢失
5.3 无障碍设计建议
对于喝水提醒这类高频使用的健康应用,建议增加:
- 系统通知提醒:通过
@ohos.notification定时发送喝水通知 - 振动反馈:每次喝水时提供短暂振动
- 语音播报:鼓励语通过 TTS 语音读出来
六、可扩展思路
- 历史记录与统计:使用
@ohos.data.preferences持久化每日饮水数据,显示周/月趋势图。 - 自定义杯量:允许用户设置不同的杯量(如 250ml、300ml),适配不同水杯。
- 定时提醒:利用后台任务定时发送喝水通知,每隔 1-2 小时提醒一次。
- 多主题:支持不同的水杯样式和背景主题,增加趣味性。
- 喝水挑战:加入连续达标天数的统计,用游戏化方式激励用户。
七、总结
喝水提醒应用以 83 行简洁代码,实现了一个完整的健康追踪工具。它的核心价值在于:
- Stack 层叠实现复杂视觉:水杯 + 水位 + 文字的叠加,展示了 Stack 在可视化组件中的强大能力
- 动态高度驱动进度显示:用
@State控制 Column 高度,替代了传统的 Progress 组件 - 计算属性简化业务逻辑:
progress、totalMl、encouragement三个 getter 将原始数据转化为展示信息 - 正向激励设计:通过鼓励语和可视化进度,利用心理学原理帮助用户养成好习惯
这个应用的代码模式——状态驱动的动态尺寸变化 + 层叠布局的可视化——可以轻松复用到电池电量显示、存储空间指示器、技能升级条等场景。
下一期我们将继续健康主题,探讨一个更具互动性的应用——计步器(Pedometer),学习如何使用 Progress 的环形样式和 Ring 类型,打造精美的运动数据看板。
本文是 HarmonyOS 应用开发实战系列第 33 期,更多内容请关注专栏。
更多推荐


所有评论(0)