在这里插入图片描述

概述

体重记录应用是 HarmonyOS 应用生态中的一个典型健康追踪类应用。本文基于 entry/src/main/ets/pages/life/WeightRecord.ets 的实现,深入剖析该应用的技术架构、核心数据结构和关键算法实现。该应用实现了体重数据的记录、存储、统计展示以及 BMI 健康指标计算等功能,采用 HarmonyOS 官方推荐的 ArkUI 声明式开发范式,充分利用了 @State 状态管理、Grid 网格布局、Slider 滑块组件等原生能力。

应用的核心技术特点包括:使用 TypeScript interface 静态类型系统定义数据结构,确保代码的类型安全;采用 Slider 组件实现直观的体重数值输入;通过 Grid 网格布局展示多维度统计数据;实现 BMI 计算算法并根据体质分类动态调整颜色提示。整个应用遵循模块化设计原则,数据存储、业务逻辑和 UI 渲染层分离,便于维护和扩展。


1. 技术架构分析

1.1 整体架构设计

体重记录应用采用经典的三层架构模式,将界面展示层、业务逻辑层和数据持久层进行了清晰分离。这种分层设计遵循了 HarmonyOS 应用开发的设计原则,使得各层职责明确,耦合度低,便于独立开发和测试。

┌─────────────────────────────────────────────────────────────┐
│                      UI 展示层                                │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
│  │ CommonTitleBar │ │  Slider输入  │ │  Grid统计   │            │
│  └─────────────┘ └─────────────┘ └─────────────┘            │
├─────────────────────────────────────────────────────────────┤
│                      业务逻辑层                               │
│  ┌─────────────┐ ┌─────────────┐ ┌─────────────┐            │
│  │ app_addRecord │ │ app_deleteRecord │ │ app_getStats │    │
│  └─────────────┘ └─────────────┘ └─────────────┘            │
│  ┌─────────────┐ ┌─────────────┐                            │
│  │ app_getBMI  │ │ app_getBMICategory │                      │
│  └─────────────┘ └─────────────┘                            │
├─────────────────────────────────────────────────────────────┤
│                      数据持久层                               │
│  ┌─────────────────────────────────────────────────┐        │
│  │              AppStorage 工具类                    │        │
│  │  app_setString / app_getString / app_setNumber  │        │
│  └─────────────────────────────────────────────────┘        │
└─────────────────────────────────────────────────────────────┘

UI 展示层完全基于 ArkUI 声明式范式构建,所有界面元素都通过 @Component 装饰器标注的组件结构声明。组件内部使用 @State 装饰器管理可变状态,当状态变化时,框架自动触发 UI 重新渲染。业务逻辑层封装在组件的方法中,包括记录的增删改查、统计数据的计算、BMI 的算法实现等。数据持久化则通过 AppStorage 工具类封装 preferences API 完成,提供同步的 get 操作和异步的 put 操作。

1.2 模块依赖关系

应用的主要依赖关系清晰明了。WeightRecord 组件直接依赖 CommonTitleBar 通用标题栏组件和 AppStorage 存储工具类。CommonTitleBar 进一步依赖 AppRouter 路由工具实现页面导航。这种依赖结构符合单向依赖原则,避免了循环依赖问题。

WeightRecord.ets
    ├── CommonTitleBar.ets
    │       └── router.ets (AppRouter)
    └── storage.ets (AppStorage)
            └── @ohos.data.preferences

值得注意的是,AppStorage 底层使用了 HarmonyOS 提供的 dataPreferences 模块,这是官方推荐的应用本地数据存储方案。相比于直接使用文件操作,preferences API 提供了更高级的键值对存储抽象,自动处理序列化反序列化,API 更加简洁易用。

1.3 状态管理机制

应用采用 HarmonyOS 原生的响应式状态管理机制。组件级别的状态通过 @State 装饰器声明,这些状态变量具有以下特性:私有性(只能在组件内部访问)、响应性(值变化会触发 UI 更新)、可变性和继承性(子组件可以通过父组件传递参数获取状态)。

@State app_records: App_WeightRecord[] = [];      // 体重记录列表
@State app_currentWeight: number = 60;             // 当前输入体重值
@State app_note: string = '';                      // 备注信息
@State app_targetWeight: number = 55;             // 目标体重
@State app_minWeight: number = 30;                // 体重范围下限
@State app_maxWeight: number = 150;               // 体重范围上限

当用户操作 Slider 改变 app_currentWeight 值时,框架检测到状态变化,自动重新执行组件的 build 方法,UI 中所有引用该状态变量的地方都会反映最新值。这种声明式状态管理大大简化了 UI 更新逻辑,开发者无需手动操作 DOM 或调用渲染方法,只需关注状态变化本身。


2. 核心数据结构

2.1 体重记录接口定义

应用使用 TypeScript interface 静态类型定义了体重记录的数据结构,这是 ArkTS 静态类型检查的基础。

interface App_WeightRecord {
  app_date: string;
  app_weight: number;
  app_note: string;
}

该接口包含三个字段:app_date 为字符串类型,记录体重数据的日期,格式为本地化的中文日期字符串(如 “2026/6/17”);app_weight 为 number 类型,记录体重数值,单位为千克;app_note 为字符串类型,可选的备注信息,用于用户记录当天的特殊状况如饮食、运动等。

采用 interface 定义数据结构有多方面优势。首先,静态类型检查可以在编译阶段发现类型错误,避免运行时类型异常。其次,明确的字段定义提供了自文档化效果,代码可读性高。再次,IDE 可以基于类型提供智能补全和类型检查提示,提升开发效率。在 ArkTS 中,interface 被编译成 ArkUI 框架内部的高效数据结构,兼顾类型安全和运行时性能。

2.2 数据结构与 JSON 序列化

体重记录列表在存储时需要序列化 为 JSON 字符串。应用使用 JSON.parse()JSON.stringify() 完成双向转换。

// 从存储加载记录
const app_storedRecords: string = app_getString('weight_records', '[]');
try {
  this.app_records = JSON.parse(app_storedRecords);
} catch (error) {
  this.app_records = [];
}

// 保存记录到存储
app_setString('weight_records', JSON.stringify(this.app_records));

这里使用了 try-catch 包裹 JSON.parse 操作,以防存储数据损坏导致解析失败。解析失败时采用防御性编程策略,将记录列表置为空数组,确保应用不会因数据异常而崩溃。默认值 '[]' 使用空 JSON 数组字符串,这样即使存储键不存在,也能保证 parse 操作成功。


3. 核心代码模块详解

3.1 数据管理模块

数据管理模块负责体重记录的增删改查操作,是应用业务逻辑的核心部分。该模块实现了三个主要方法:app_addRecord 用于添加新记录、app_deleteRecord 用于删除历史记录、app_saveRecords 用于持久化存储。

3.1.1 添加记录功能
app_addRecord(): void {
  const app_newRecord: App_WeightRecord = {
    app_date: new Date().toLocaleDateString('zh-CN'),
    app_weight: this.app_currentWeight,
    app_note: this.app_note.trim()
  };
  this.app_records.unshift(app_newRecord);
  this.app_note = '';
  this.app_saveRecords();
}

添加记录方法的实现逻辑清晰。首先构建一个新的记录对象,日期使用 toLocaleDateString('zh-CN') 获取本地化格式的中文日期。体重值直接取自当前输入状态 app_currentWeight,这是用户通过 Slider 输入的数值。备注信息使用 trim() 方法去除首尾空白字符,防止无效空白数据存入列表。

新记录通过 unshift() 方法插入到数组开头,这保证了最新记录总是出现在列表最前面,符合时间线展示的直觉。添加完成后,清空备注输入框,为下次输入做准备。最后调用 app_saveRecords() 将更新后的完整列表同步到持久化存储。

3.1.2 删除记录功能
app_deleteRecord(app_index: number): void {
  this.app_records.splice(app_index, 1);
  this.app_saveRecords();
}

删除记录使用数组的 splice() 方法,从指定索引位置删除一个元素。参数 app_index 对应 ForEach 遍历时的索引值。由于列表采用 unshift() 方式添加,最新记录索引为 0,越早的记录索引越大,这与用户查看列表的顺序完全对应。

删除操作后立即调用 app_saveRecords() 同步存储,确保数据一致性。这里没有做数组越界检查,因为 ForEach 的索引范围天然被数组长度限制,但在生产环境中建议增加防御性检查。

3.1.3 存储抽象层
app_saveRecords(): void {
  app_setString('weight_records', JSON.stringify(this.app_records));
}

存储操作通过 AppStorage 工具类完成,该类封装了 preferences API 的复杂操作。app_setString() 方法接受键名和字符串值,将数据异步写入本地存储。相比于直接调用 preferences API,AppStorage 提供了同步的 get 操作和简化的 put 接口,错误处理也更友好。

3.2 统计计算模块

统计计算模块提供数据分析和指标计算功能,是体重记录应用的核心算法部分。该模块包含 app_getStats() 统计方法以及 BMI 相关的三个辅助方法。

3.2.1 统计方法实现
app_getStats(): { app_current: number; app_avg: number; app_max: number; app_min: number; app_diff: number } {
  if (this.app_records.length === 0) {
    return { app_current: 0, app_avg: 0, app_max: 0, app_min: 0, app_diff: 0 };
  }
  const app_weights: number[] = this.app_records.map((app_r: App_WeightRecord) => app_r.app_weight);
  const app_current: number = app_weights[0];
  const app_avg: number = parseFloat((app_weights.reduce((a: number, b: number) => a + b, 0) / app_weights.length).toFixed(1));
  const app_max: number = Math.max(...app_weights);
  const app_min: number = Math.min(...app_weights);
  const app_diff: number = parseFloat((app_current - this.app_targetWeight).toFixed(1));
  return { app_current, app_avg, app_max, app_min, app_diff };
}

统计方法首先处理空列表的边界情况,返回全零对象避免后续计算错误。然后使用 map() 提取所有体重值生成新数组,这是函数式编程的典型用法,代码简洁且表达意图清晰。

当前体重取数组第一个元素,即最新录入的体重值。平均值通过 reduce() 累加求和后除以元素个数,再使用 toFixed(1) 保留一位小数,最后 parseFloat() 转回数值类型。最大值和最小值分别使用 Math.max()Math.min() 的展开语法计算。距离目标的差值用当前体重减去目标体重,正值表示超过目标,负值表示低于目标。

返回值为内联声明的对象类型,明确了五个统计指标的组成。这种写法省去了额外定义接口的步骤,代码更紧凑,适合内部使用的临时数据结构。

3.2.2 BMI 计算方法
app_getBMI(app_weight: number): number {
  const app_height: number = 1.7;
  return parseFloat((app_weight / (app_height * app_height)).toFixed(1));
}

BMI(Body Mass Index,身体质量指数)是衡量人体肥胖程度的国际通用指标。计算公式为体重(千克)除以身高(米)的平方。方法中硬编码身高为 1.7 米,这是一个简化处理,实际应用中应该允许用户设置个人身高数据。返回值同样保留一位小数,保持数据精度一致性。

3.2.3 BMI 分类方法
app_getBMICategory(app_bmi: number): string {
  if (app_bmi < 18.5) return '偏瘦';
  if (app_bmi < 24) return '正常';
  if (app_bmi < 28) return '偏胖';
  return '肥胖';
}

BMI 分类采用中国成人标准,这是根据中国国情调整后的分类体系:

BMI 范围 分类 说明
< 18.5 偏瘦 体重过低,可能存在营养不良风险
18.5 ~ 24 正常 健康体重范围
24 ~ 28 偏胖 超重,需要关注饮食和运动
>= 28 肥胖 肥胖标准,建议咨询医生
3.2.4 BMI 颜色映射方法
app_getBMIColor(app_bmi: number): string {
  if (app_bmi < 18.5) return '#52C41A';
  if (app_bmi < 24) return '#007DFF';
  if (app_bmi < 28) return '#FAAD14';
  return '#FF4D4F';
}

BMI 颜色方法返回十六进制颜色代码,与 UI 设计系统的颜色定义保持一致:

BMI 分类 颜色代码 颜色名称 语义
偏瘦 #52C41A 绿色 提示用户注意营养摄入
正常 #007DFF 蓝色 表示健康状态
偏胖 #FAAD14 黄色 警告用户注意体重管理
肥胖 #FF4D4F 红色 强烈建议采取行动

颜色语义符合直觉心理学原理:绿色代表正常通行,蓝色给人安心感觉,黄色提醒注意,红色警示危险。用户扫一眼颜色就能快速判断当前体重状态,无需阅读具体数值。

3.3 UI 组件模块

UI 组件模块是应用的可视化层,完全采用 ArkUI 声明式范式构建。所有 UI 元素都作为组件树的节点声明,数据驱动渲染,开发者无需手动操作视图更新。

3.3.1 标题栏组件
CommonTitleBar({
  app_title: '体重记录',
  app_showBack: true
})

标题栏是应用的通用导航组件,传入标题文本和返回按钮显示标志两个参数。组件内部实现包含返回按钮、图片资源和标题文本的布局,返回按钮点击时调用 AppRouter.app_back() 返回上一页面。这种通用组件抽取避免了代码重复,提升了项目的一致性和可维护性。

3.3.2 Slider 体重输入组件
Slider({
  value: this.app_currentWeight,
  min: this.app_minWeight,
  max: this.app_maxWeight,
  step: 0.1
})
  .blockColor($r('app.color.app_color_primary'))
  .trackColor('#E5E5E5')
  .selectedColor($r('app.color.app_color_primary'))

Slider 是 HarmonyOS 提供的原生滑块组件,非常适合体重这类连续数值的选择场景。核心配置参数说明:

参数 说明
value app_currentWeight 绑定状态变量,双向同步
min 30 体重下限,单位 kg
max 150 体重上限,单位 kg
step 0.1 步进值,支持精确到小数

样式配置中,blockColor 设置滑块颜色,trackColor 设置轨道默认颜色,selectedColor 设置已选择部分的轨道颜色。通过 $r('app.color.app_color_primary') 引用应用主题色,保持视觉一致性。Slider 组件的 onChange 事件在用户拖动时触发(ARKUI具体行为),默认情况下状态变量会自动更新,无需额外处理。

3.3.3 Grid 统计网格组件
Grid() {
  GridItem() {
    Column({ space: 8 }) {
      Text('当前')
        .fontSize(14)
        .fontColor($r('app.color.app_color_text_secondary'))
      Text(`${this.app_getStats().app_current} kg`)
        .fontSize(18)
        .fontWeight(FontWeight.Bold)
        .fontColor($r('app.color.app_color_text_primary'))
    }
    // ... 样式配置
  }
  // ... 其他 GridItem
}
.columnsTemplate('1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.width('100%')

Grid 网格布局组件用于以网格形式展示统计数据。通过 columnsTemplate('1fr 1fr') 设置两列等宽布局,columnsGaprowsGap 分别设置列间距和行间距。GridItem 作为 Grid 的子元素,每个代表一个统计卡片。

四个统计卡片分别展示当前体重、平均体重、距离目标差值和 BMI 指数。前三个卡片的内容通过 app_getStats() 方法获取,BMI 卡片额外使用 app_getBMIColor() 动态设置颜色。距离目标差值根据正负情况使用不同颜色:超过目标显示危险色,低于或达到目标显示成功色。

Grid 布局的优势在于自动处理行列排列,添加或删除数据时无需调整布局代码,框架会自动计算网格尺寸。这比使用 Row 和 Column 嵌套实现网格更加简洁且易于维护。

3.3.4 历史记录列表组件
Scroll() {
  Column({ space: 8 }) {
    ForEach(this.app_records, (app_record: App_WeightRecord, app_index: number) => {
      Row({ space: 12 }) {
        Column({ space: 4 }) {
          Text(app_record.app_date)
            .fontSize(14)
            .fontColor($r('app.color.app_color_text_secondary'))
          if (app_record.app_note) {
            Text(app_record.app_note)
              .fontSize(12)
              .fontColor($r('app.color.app_color_text_tertiary'))
          }
        }
        .width('flexGrow')

        Text(`${app_record.app_weight} kg`)
          .fontSize(16)
          .fontWeight(FontWeight.Medium)
          .fontColor($r('app.color.app_color_text_primary'))

        Button('删除')
          .onClick(() => this.app_deleteRecord(app_index))
      }
      // ... 样式配置
    })
  }
  .width('100%')
}
.width('100%')
.height(200)

历史记录列表使用 Scroll 滚动容器包裹 ForEach 循环渲染的记录项。Scroll 提供了垂直滚动能力,当记录数量超过显示区域时可以滚动查看。ForEach 是 ArkUI 的列表渲染语法,第一个参数是数据源数组,第二个参数是渲染回调函数,接收单个数据项和索引。

每个记录项布局采用水平 Row 容器,左侧是日期和备注信息(使用 Column 实现垂直排列),中间是体重数值,右侧是删除按钮。备注信息使用 if 条件渲染,只有存在备注内容时才显示,避免空行影响布局美观。删除按钮通过 onClick 事件绑定删除方法,传入当前记录的索引值。

高度固定为 200vp,这是一个经验值,兼顾了显示效率和屏幕空间利用。如果记录数量少,剩余空间会留白;如果记录多,滚动查看是合理的用户体验设计。

3.5 生命周期管理模块

HarmonyOS 应用组件具有完整的生命周期钩子,WeightRecord 组件使用了 aboutToAppearaboutToDisappear 两个最重要的生命周期回调。

3.5.1 组件即将显示时
aboutToAppear(): void {
  const app_storedRecords: string = app_getString('weight_records', '[]');
  try {
    this.app_records = JSON.parse(app_storedRecords);
  } catch (error) {
    this.app_records = [];
  }
  this.app_targetWeight = app_getNumber('weight_target', 55);
  if (this.app_records.length > 0) {
    this.app_currentWeight = this.app_records[0].app_weight;
  }
}

aboutToAppear 在组件即将显示前调用,是初始化数据的好时机。方法中完成三项初始化工作:首先从持久化存储加载体重记录列表,使用 try-catch 处理可能的 JSON 解析异常;然后加载用户之前设置的目标体重,如果不存在则使用默认值 55kg;最后,如果有历史记录,将当前输入体重初始化为最新一条记录的体重值,方便用户在此基础上微调录入新数据。

3.5.2 组件即将销毁时
aboutToDisappear(): void {
  app_setString('weight_records', JSON.stringify(this.app_records));
  app_setNumber('weight_target', this.app_targetWeight);
}

aboutToDisappear 在组件即将销毁前调用,是保存数据的关键时机。方法将当前记录列表和目标体重同步到持久化存储。由于 preferences 的 put 操作是异步的,这里直接调用 app_setStringapp_setNumber,它们内部会处理异步写入,组件销毁不会等待写入完成。这种设计在大多数场景下是安全的,但如果应用在写入完成前被强制终止,可能导致数据丢失。更严格的场景可以使用 aboutToDisappear 返回 Promise 并等待完成。


4. 数据持久化机制

4.1 AppStorage 工具类设计

AppStorage 是应用级别的数据存储抽象层,封装了 HarmonyOS 的 preferences API,提供简洁统一的存储接口。

export class AppStorage {
  static async app_setString(app_key: string, app_value: string): Promise<void> {
    if (app_pref_instance !== null) {
      try {
        await app_pref_instance.putSync(app_key, app_value);
        await app_pref_instance.flushSync();
      } catch (error) {
        console.error(`存储设置失败: ${error}`);
      }
    }
  }

  static app_getString(app_key: string, app_defaultValue: string): string {
    if (app_pref_instance !== null) {
      try {
        return app_pref_instance.getSync(app_key, app_defaultValue) as string;
      } catch (error) {
        console.error(`存储获取失败: ${error}`);
        return app_defaultValue;
      }
    }
    return app_defaultValue;
  }
  // ... 其他方法类似
}

该工具类的设计有几个值得注意的点。set 操作设计为异步方法(async),内部使用 putSync 配合 flushSync 确保数据写入底层存储。get 操作设计为同步方法,直接返回结果,使用更方便。两种操作都包含完善的异常处理,失败时记录日志并返回默认值。类型参数使用泛型约束,返回值通过类型断言转换,确保类型安全。

4.2 存储数据结构

应用使用两个存储键管理数据:

存储键 数据类型 说明
weight_records JSON字符串 App_WeightRecord[] 数组序列化
weight_target number 用户目标体重,单位 kg

这种简单的键值对存储适合小规模数据场景。weight_records 作为 JSON 数组字符串存储,支持任意数量的记录,每条记录包含日期、体重和备注三个字段。weight_target 作为单独的数字值存储,允许用户独立调整目标体重而不影响记录数据。


5. BMI 算法与健康指标体系

5.1 BMI 算法原理

BMI(Body Mass Index,身体质量指数)是目前国际通用的衡量人体胖瘦程度以及是否健康的指标。计算公式简单直观:

BMI = 体重(kg) ÷ 身高(m)²

以体重 65kg、身高 1.7m 为例:

BMI = 65 ÷ (1.7 × 1.7) = 65 ÷ 2.89 ≈ 22.5

方法实现代码:

app_getBMI(app_weight: number): number {
  const app_height: number = 1.7;
  return parseFloat((app_weight / (app_height * app_height)).toFixed(1));
}

5.2 BMI 分类标准

应用采用中国成人 BMI 分类标准,这是《中国居民膳食指南》推荐的标准:

┌────────────────────────────────────────────────────────────┐
│  BMI 分类对照表                                             │
├─────────────┬──────────────┬──────────────────────────────┤
│   BMI范围   │    分类      │            建议               │
├─────────────┼──────────────┼──────────────────────────────┤
│   < 18.5    │    偏瘦      │  注意营养均衡,增加蛋白质摄入    │
│  18.5~24    │    正常      │  保持现有生活方式               │
│   24~28     │    偏胖      │  控制饮食,适量增加运动         │
│    ≥ 28     │    肥胖      │  建议咨询医生,制定减重计划      │
└─────────────┴──────────────┴──────────────────────────────┘

5.3 颜色语义设计

BMI 颜色映射是典型的语义化颜色设计案例:

app_getBMIColor(app_bmi: number): string {
  if (app_bmi < 18.5) return '#52C41A';  // 绿色 - 通行/正常
  if (app_bmi < 24) return '#007DFF';    // 蓝色 - 安全/可信
  if (app_bmi < 28) return '#FAAD14';   // 黄色 - 警告/注意
  return '#FF4D4F';                      // 红色 - 危险/紧急
}

这种颜色梯度设计遵循色彩心理学的直觉联想原则,用户无需阅读文字就能感知健康状态。实际应用中,绿色和蓝色属于安全色系,黄色属于警示色系,红色属于禁止/危险色系。颜色与应用主题色 #007DFF(蓝色)保持一致,只有在异常状态时才使用其他颜色,形成了良好的视觉层次。


6. 页面布局结构分析

6.1 整体布局架构

页面采用垂直布局(Column),从头到尾依次排列各个功能区块:

Column (根容器)
├── CommonTitleBar (标题栏,高度56)
├── Column (内容区,flexGrow)
│   ├── Column (体重输入区)
│   │   ├── Text ('当前体重')
│   │   ├── Row (数值展示)
│   │   ├── Slider (体重滑块)
│   │   ├── TextField (备注输入)
│   │   └── Button ('记录')
│   ├── Column (目标体重区)
│   │   ├── Text ('目标体重')
│   │   └── Row (Slider + 数值)
│   ├── Column (统计区,条件渲染)
│   │   ├── Text ('统计数据')
│   │   └── Grid (2x2 网格)
│   └── Column (历史记录区,条件渲染)
│       ├── Text ('历史记录')
│       └── Scroll + ForEach (列表)

这种自上而下的线性布局符合移动端用户的阅读习惯,重要信息(体重输入)放在最上方便于操作,次要信息(历史记录)放在下方可以通过滚动查看。

6.2 条件渲染策略

统计区和历史记录区使用 if 条件渲染,只有当存在记录时才显示:

if (this.app_records.length > 0) {
  Column({ space: 12 }) {
    // 统计区内容
  }
  
  Column({ space: 12 }) {
    // 历史记录区内容
  }
}

这种设计有两个好处:空状态下页面更简洁,不会显示空洞的统计卡片或空列表提示;避免在无数据时计算统计值,减少不必要的计算开销。条件渲染是 ArkUI 声明式范式的核心特性,状态驱动渲染,代码比传统的 show/hide 模式更简洁。

6.3 响应式设计考虑

布局中使用了一些响应式设计的技巧:

  • 宽度统一使用 '100%',自适应屏幕宽度
  • 内边距使用固定值(16vp),保持内容与边缘的安全距离
  • Grid 使用 1fr 1fr 等分列,自适应不同屏幕宽度
  • 高度使用固定值或内容自适应,避免溢出

这些设计使得应用能够适配不同尺寸的 HarmonyOS 设备,从手机到平板都有合理的显示效果。


7. 关键代码片段速查

7.1 数据结构定义

interface App_WeightRecord {
  app_date: string;
  app_weight: number;
  app_note: string;
}

7.2 状态变量声明

@State app_records: App_WeightRecord[] = [];
@State app_currentWeight: number = 60;
@State app_note: string = '';
@State app_targetWeight: number = 55;
@State app_minWeight: number = 30;
@State app_maxWeight: number = 150;

7.3 Slider 组件配置

Slider({
  value: this.app_currentWeight,
  min: this.app_minWeight,
  max: this.app_maxWeight,
  step: 0.1
})
  .blockColor($r('app.color.app_color_primary'))
  .trackColor('#E5E5E5')
  .selectedColor($r('app.color.app_color_primary'))

7.4 Grid 布局配置

Grid() {
  // GridItem 元素
}
  .columnsTemplate('1fr 1fr')
  .columnsGap(8)
  .rowsGap(8)
  .width('100%')

7.5 BMI 计算与分类

app_getBMI(app_weight: number): number {
  const app_height: number = 1.7;
  return parseFloat((app_weight / (app_height * app_height)).toFixed(1));
}

app_getBMICategory(app_bmi: number): string {
  if (app_bmi < 18.5) return '偏瘦';
  if (app_bmi < 24) return '正常';
  if (app_bmi < 28) return '偏胖';
  return '肥胖';
}

app_getBMIColor(app_bmi: number): string {
  if (app_bmi < 18.5) return '#52C41A';
  if (app_bmi < 24) return '#007DFF';
  if (app_bmi < 28) return '#FAAD14';
  return '#FF4D4F';
}

7.6 存储操作

// 保存
app_setString('weight_records', JSON.stringify(this.app_records));
app_setNumber('weight_target', this.app_targetWeight);

// 加载
const app_storedRecords: string = app_getString('weight_records', '[]');
this.app_records = JSON.parse(app_storedRecords);
this.app_targetWeight = app_getNumber('weight_target', 55);

8. 技术总结与扩展建议

8.1 技术亮点

  1. 声明式 UI 范式:整个界面完全采用 ArkUI 声明式语法,状态驱动渲染,代码简洁易维护
  2. 静态类型系统:使用 interface 定义数据结构,编译时类型检查保障代码质量
  3. 模块化设计:通用组件(CommonTitleBar)和工具类(AppStorage)分离复用
  4. BMI 健康指标:完整的 BMI 计算、分类和可视化体系
  5. 数据持久化:preferences API 封装合理,支持异步写入和同步读取

8.2 潜在改进点

  1. 身高数据:当前 BMI 计算使用硬编码身高 1.7m,应支持用户设置个人身高
  2. 数据导出:可增加导出 CSV/Excel 功能,方便用户在其他平台分析数据
  3. 图表展示:可增加体重趋势折线图,直观展示一段时间的体重变化
  4. 提醒功能:可结合通知能力,在设定时间提醒用户记录体重
  5. 数据备份:可接入云同步能力,实现多设备数据同步

8.3 ArkUI 开发经验

通过体重记录应用的分析,可以总结以下 ArkUI 开发经验:

  • 优先使用 @State 管理组件内状态,需要跨组件共享时考虑 @StorageLink 或应用级状态管理
  • Slider 组件适合连续数值输入,List/Grid 适合展示列表数据,Scroll 包裹实现滚动
  • 数据存储优先使用 preferences API,更复杂的需求考虑关系型数据库或分布式存储
  • 颜色使用 $r('app.color.xxx') 引用资源定义,便于主题切换和深色模式支持
  • 生命周期方法中执行初始化和清理工作,注意异步操作的时序问题

结语

体重记录应用虽然功能简单,但涵盖了 HarmonyOS 应用开发的多个核心知识点:界面组件使用、状态管理、数据存储、业务逻辑封装、算法实现等。通过对该应用的深入分析,可以掌握 ArkUI 声明式开发的基本范式,为开发更复杂的 HarmonyOS 应用打下坚实基础。

应用的模块化架构和清晰的代码组织方式,使其成为一个良好的学习参考案例。建议读者在实际开发中借鉴其设计思路,并根据自己的业务需求进行扩展和优化。

Logo

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

更多推荐