鸿蒙 ArkTS 实战:Stretch Timer 从健康数据到交互面板完整解析

前言

拉伸计时器 是一个面向 健康记录与运动管理 的鸿蒙 ArkTS 小应用。管理拉伸动作、当前动作、剩余秒数、计划开关和完成反馈。 本文基于 entry/src/main/ets/pages/Index.ets 的真实源码结构展开,分析它的 数据模型@State 状态业务方法Builder 组件 和页面布局,形成一篇可直接发布的 CSDN 技术文章。

在这里插入图片描述

图示说明:页面以健康数据记录、目标追踪、趋势反馈和操作按钮为核心,适合做健康类 ArkTS 单页应用练习。

一、应用定位与业务闭环

1.1 场景定位

Stretch Timer 面向日常健康管理。用户可以记录数据、查看趋势、推进计划或完成打卡,页面会根据状态变化即时刷新结果。

业务环节 页面表现 技术落点
数据记录 输入框、按钮、列表 TextInput、Button、ForEach
目标追踪 数值、百分比、连续天数 private 计算方法
状态反馈 提示文案和颜色 @State 驱动
趋势展示 条目卡片或趋势行 Builder 组件
操作闭环 添加、完成、导出、打卡 业务方法

1.2 阅读路径

  1. 先确认接口定义,理解业务数据结构。
  2. 再分析状态字段,判断页面刷新来源。
  3. 接着拆解方法,明确新增、统计、完成和反馈动作。
  4. 最后看 Builder,理解重复 UI 如何组织。

核心原则:健康类小工具的数据必须可追踪,状态必须少而明确,反馈必须在用户操作后立即出现。

二、工程结构与入口页面

2.1 目录结构

核心代码位于 entry/src/main/ets/pages/Index.ets。

Stretch Timer
├── AppScope
├── entry
│   └── src
│       └── main
│           ├── ets
│           │   └── pages
│           │       └── Index.ets
│           └── module.json5
├── hvigor
├── build-profile.json5
└── oh-package.json5

2.2 页面入口

@Entry
@Component
struct Index {
  build() {
    Scroll() {
      Column() {
        // 健康数据面板
      }
    }
  }
}

2.3 技术组成

技术点 作用 本项目价值
ArkTS 类型和逻辑 组织健康数据
ArkUI 声明式 UI 构建页面结构
@State 响应式状态 触发界面刷新
@Builder UI 片段复用 统一卡片和趋势样式
Hvigor 构建工具 生成鸿蒙应用包

三、数据模型设计

3.1 接口清单

源码中的接口包括:$iface。

interface StretchAction {
  id: number;
  title?: string;
  value?: number;
  done?: boolean;
  note?: string;
}

如果项目没有单独定义接口,它会直接通过 @State 保存核心字段,例如阶段、秒数、声音、分钟数和连续天数。

3.2 字段分类

字段类型 常见字段 作用
标识字段 id 列表渲染 key
记录字段 steps、weight、score、pressure 健康指标
状态字段 done、phase、message 操作反馈
目标字段 goal、 argetDays、minutes 目标追踪
分类字段 ype、category、sound 筛选或模式切换

3.3 模型价值

健康类应用不是只展示一个数字,而是要让数字和日期、目标、趋势、动作关联起来。接口定义让每条记录更稳定,也便于后续接入本地存储。

四、@State 状态拆解

4.1 状态清单

项目中的状态包括:$state。

@State records: StretchAction[] = [];
@State draftValue: string = '';
@State goal: number = 0;
@State message: string = '';

4.2 状态分类表

状态类别 示例 说明
列表状态 $primaryState 保存记录或动作列表
输入状态 weightDraft、sysDraft、draft 接收用户输入
目标状态 goal、 argetDays、minutes 计算完成度
运行状态
emaining、seconds、phase 控制计时或训练节奏
反馈状态 message、
eport 展示操作结果

4.3 状态更新策略

列表类状态使用新数组替换,计时类状态直接更新当前数值。

private addRecord(): void {
  const item: StretchAction = {
    id: Date.now(),
    title: '新记录',
    done: false
  };
  this.records = [item, ...this.records];
}

五、核心方法解析

5.1 方法清单

源码中的核心方法包括:$method。

方法类型 作用 典型场景
统计方法 计算百分比、平均值、异常数 步数、体重、血压
新增方法 写入新记录 饮食、体重、跑步
计时方法 推进剩余秒数 拉伸、冥想
打卡方法 记录完成状态 戒糖、训练
趋势方法 渲染历史走势 体重、步数、训练

5.2 新增记录

private addEntry(): void {
  const value = this.draftValue.trim();
  if (value.length === 0) {
    return;
  }
  this.records = [{ id: Date.now(), title: value, done: false }, ...this.records];
  this.draftValue = '';
}

5.3 统计计算

private progress(): number {
  if (this.goal === 0) {
    return 0;
  }
  return Math.min(100, Math.round(this.currentValue / this.goal * 100));
}

5.4 完成动作

private finish(id: number): void {
  this.records = this.records.map((item: StretchAction) => {
    return item.id === id ? { ...item, done: true } : item;
  });
}

六、Builder 组件复用

6.1 Builder 清单

源码中的 Builder 组件包括:$builder。

@Builder
private card(item: StretchAction) {
  Column() {
    Text(item.title ?? '记录')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)
  }
  .padding(14)
  .backgroundColor('#FFFFFF')
  .borderRadius(8)
}

6.2 复用价值

Builder 适用内容 价值
card 历史记录、动作条目 统一列表样式
rend 趋势数据 统一可视化结构
abs 分类切换 统一选中态
soundTabs 声音模式 统一模式按钮

6.3 分工边界

Builder 不处理复杂计算,只接收状态并渲染 UI。计算逻辑放在 private 方法中,能降低页面耦合。

七、页面布局结构

7.1 常见结构

Scroll() {
  Column() {
    // 顶部目标区
    // 输入区
    // 趋势区
    // 记录列表
  }
  .padding(16)
}
.backgroundColor('#F6F8FA')

7.2 页面分区

区域 内容 作用
顶部目标区 当前值、目标、百分比 形成即时反馈
输入区 数值或文本输入 写入记录
控制区 计时、模式、声音 控制训练流程
趋势区 周数据或历史记录 观察变化
记录区 卡片列表 复盘历史

7.3 列表渲染

ForEach(this.records, (item: StretchAction) => {
  this.card(item)
}, (item: StretchAction) => item.id.toString())

八、交互链路

8.1 输入链路

TextInput({ text: this.draftValue })
  .onChange((value: string) => {
    this.draftValue = value;
  })

8.2 操作链路

Button('记录')
  .onClick(() => {
    this.addEntry();
  })

8.3 反馈链路

private setMessage(text: string): void {
  this.message = text;
}

实现重点:输入只改草稿状态,按钮只调用方法,方法只更新状态,UI 只读取状态。

九、健康数据的可视化表达

9.1 指标类型

指标 表达方式 适用项目
百分比 进度条、数字 步行目标、戒糖目标
趋势 历史列表、折线模拟 体重、步数
计时 秒数、阶段 拉伸、冥想
异常 红色标签 血压记录
热量 数值统计 饮食照片日记

9.2 颜色语义

绿色表示完成或正常,橙色表示待关注,红色表示异常,蓝色表示当前模式或主操作。

9.3 文案策略

健康类工具要避免模糊文案。按钮应直接写“记录”“打卡”“完成”“导出”,状态应明确写“正常”“异常”“已完成”“进行中”。

十、运行与调试

10.1 DevEco Studio 运行

# 打开项目目录
# 同步依赖
# 选择 entry 模块
# 运行到模拟器或真机

10.2 Hvigor 构建

hvigorw clean
hvigorw assembleHap

10.3 调试关注点

调试项 判断标准
输入更新 onChange 后状态变化
目标计算 百分比不超过 100
计时逻辑 秒数或阶段可推进
列表刷新 新增后记录出现在页面
异常判断 标签颜色和统计一致

十一、可维护性分析

11.1 文件规模

当前 Index.ets 约 78 行,适合作为单页健康工具示例。后续复杂度提高时,可以拆分为目标卡、输入表单、趋势图和记录列表组件。

11.2 状态来源

能从记录列表计算出的值,不需要额外保存为状态。这样能避免统计值和源数据不一致。

private recordCount(): number {
  return this.records.length;
}

11.3 输入校验

健康数据通常需要基础校验,例如数字必须大于 0,血压值需要区间判断,体重和热量不能为空。

十二、扩展方向

12.1 本地存储

interface HealthRecordStore {
  id: number;
  type: string;
  payload: string;
  createdAt: number;
}

12.2 图表增强

可以加入折线图、柱状图或日历热力图,增强趋势可读性。

12.3 提醒能力

计时器、戒糖、喝水、拉伸等场景都可以继续接入通知提醒。

十三、同类模板抽象

13.1 数据模板

interface HealthItem {
  id: number;
  value: number;
  note: string;
  done: boolean;
}

13.2 状态模板

@State items: HealthItem[] = [];
@State draftValue: string = '';
@State message: string = '';

13.3 组件模板

@Builder
private itemCard(item: HealthItem) {
  Row() {
    Text(${item.value}).layoutWeight(1)
    Text(item.done ? '已完成' : '进行中')
  }
  .padding(12)
  .backgroundColor('#FFFFFF')
}

十四、实现亮点

14.1 业务模型清楚

Stretch Timer 使用 $iface 组织健康数据,能把记录、目标和反馈连接起来。

14.2 状态链路明确

$state 覆盖了页面关键状态,便于调试输入、目标、记录和反馈。

14.3 方法职责集中

$method 将统计、记录、计时和打卡逻辑集中管理,避免 UI 内直接堆业务规则。

十五、总结

Stretch Timer 是一个典型的鸿蒙 ArkTS 健康类单页应用。它通过 $iface 建模健康数据,通过 $state 保存目标、输入、运行和反馈状态,通过 $method 完成记录、统计、计时或打卡,再通过 $builder 渲染趋势和卡片。

这类应用的核心是“数据可追踪、状态可解释、反馈可感知”。掌握这套结构后,可以继续扩展更多健康管理场景,例如饮水、运动、睡眠、体重、血压、冥想和习惯打卡。

如果这篇文章对你有帮助,欢迎点赞、收藏、关注,你的支持是我持续创作的动力!


相关资源:

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐