极简早餐搭配:鸿蒙AI应用,3秒搞定你的营养早餐方案

一、引言

在快节奏的都市生活中,早餐往往是最容易被牺牲的一餐。赶公交、赶地铁、赶打卡——"早餐随便对付一口"成了无数上班族的日常写照。然而,营养学研究表明,一顿优质的早餐不仅能为全天提供充足的能量,还能显著提升工作效率和认知表现。

极简早餐搭配正是为解决这一痛点而诞生的鸿蒙原生AI应用。它运用ArkTS声明式UI框架,在HarmonyOS设备上为用户提供极速、精准、个性化的早餐搭配方案。用户只需完成两个选择——制作时间(5/10/15分钟)和早餐偏好(快手/健康/高蛋白/低碳水)——AI即刻生成3套完整的早餐方案,附带精确热量数据和可执行的做法要点。

本文将从应用架构设计、鸿蒙技术特性深度解析、AI应用亮点、技术挑战与解决方案、用户体验设计等多个维度,全面剖析这款应用的实现之道。
在这里插入图片描述

二、应用架构设计

2.1 整体架构

极简早餐搭配采用了HarmonyOS推荐的MVVM(Model-View-ViewModel)架构模式,将应用拆分为三个核心层次:

┌─────────────────────────────┐
│        View 层              │
│  BreakfastComboPage.ets     │
│  (@Entry @Component)        │
├─────────────────────────────┤
│        Model 层             │
│  BreakfastComboModel.ets    │
│  (数据模型 + 常量定义)       │
├─────────────────────────────┤
│      Service 层             │
│  BreakfastComboService.ets  │
│  (业务逻辑 + AI数据源)       │
└─────────────────────────────┘

2.2 页面结构

组成部分 实现方式 说明
欢迎引导 aboutToAppear() 生命周期 初始化消息队列,展示欢迎语
时间选择 @Builder buildSection() 复用 Flex + ForEach 渲染3个时间选项
偏好选择 @Builder buildSection() 复用 Flex + ForEach 渲染4个偏好选项
生成按钮 条件渲染(双选后出现) @State 双条件联动驱动
结果展示 @Builder buildResultCard() Scroll + ForEach 渲染3套早餐卡片

2.3 数据流设计

用户点击选项 → @State更新 → 条件渲染按钮
    ↓
点击"生成早餐搭配" → onGenerate()
    ↓
setTimeout模拟AI处理 → service.getBreakfast()
    ↓
@State currentData 更新 → buildResultCard 渲染

三、鸿蒙技术深度解析

3.1 @State 驱动下的双条件联动

这是本应用最具代表性的鸿蒙技术实践之一。页面上有两个选择维度——时间和偏好,只有当用户都完成了选择,生成按钮才会出现。这个逻辑通过 @State 装饰器的响应式特性完美实现:

@State selectedTime: string = ''
@State selectedPreference: string = ''
@State currentData: BreakfastData | null = null
@State isLoading: boolean = false

build() {
  Column() {
    // ... 选择区域 ...

    // ⭐ 双条件联动:只有两个都选好了才显示按钮
    if (this.selectedTime !== '' && this.selectedPreference !== '') {
      Text('生成早餐搭配')
        .fontSize(16)
        .fontWeight(FontWeight.Bold)
        .fontColor('#FFFFFF')
        .padding({ left: 32, right: 32, top: 12, bottom: 12 })
        .backgroundColor(COLOR_PRIMARY)
        .borderRadius(24)
        .margin({ top: 16 })
        .onClick(() => { this.onGenerate() })
    }

    // ... 结果展示区域 ...
  }
}

这里的核心机制是:当 selectedTimeselectedPreference 任一 @State 变量的值发生变化时,ArkTS框架会自动触发 build() 方法的重新执行,条件判断 if (this.selectedTime !== '' && this.selectedPreference !== '') 会实时重新评估。这种声明式UI的开发范式,让开发者只需描述"UI应该是什么状态",而无需手动操作DOM更新,大大降低了状态管理的复杂度。

3.2 @Builder 构建可复用UI卡片

@Builder 是鸿蒙ArkTS中最具生产力的特性之一,它允许开发者将UI片段封装为可复用的构建函数。在本应用中,@Builder被用于两个核心场景:

场景一:通用选择区域(参数化@Builder)

@Builder
buildSection(title: string, items: string[], selected: string, onClick: (item: string) => void) {
  Column() {
    Row() {
      Text(title).fontSize(14).fontColor(COLOR_TEXT_SEC)
      Blank()
    }
    .width('100%')
    .padding({ left: 16, top: 8 })

    Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
      ForEach(items, (item: string) => {
        Text(item)
          .fontSize(14)
          .fontWeight(selected === item ? FontWeight.Bold : FontWeight.Normal)
          .fontColor(selected === item ? COLOR_PRIMARY : COLOR_TEXT)
          .padding({ left: 14, right: 14, top: 8, bottom: 8 })
          .backgroundColor(selected === item ? COLOR_SELECTED_BG : COLOR_CARD)
          .borderRadius(16)
          .border({ width: 1, color: selected === item ? COLOR_PRIMARY : COLOR_BORDER })
          .margin({ right: 8, bottom: 8 })
          .onClick(() => { onClick(item) })
      })
    }
    .width('100%')
    .padding({ left: 16, right: 16, top: 8, bottom: 4 })
  }
}

这个 buildSection 通过参数化设计,将标题、数据数组、当前选中值和点击回调全部抽象为参数,使得时间和偏好两个选择区域可以用同一套模板渲染,代码复用率达到100%。

场景二:结果卡片(含热量标签)

@Builder
buildResultCard(data: BreakfastData) {
  Column() {
    Text('🍽️ 早餐搭配方案')
      .fontSize(16)
      .fontWeight(FontWeight.Bold)

    ForEach(data.combos, (combo: ComboEntry, idx: number) => {
      Row() {
        // 序号圆标
        Text(`${idx + 1}`)
          .width(28).height(28).borderRadius(14)
          .backgroundColor(COLOR_PRIMARY)
          .fontColor('#FFFFFF')

        Column() {
          Text(combo.name).fontSize(15).fontWeight(FontWeight.Bold)
          // 热量标签 - 胶囊样式
          Row() {
            Text(`${combo.kcal} kcal`)
              .fontSize(12)
              .fontColor('#FFFFFF')
              .padding({ left: 8, right: 8, top: 2, bottom: 2 })
              .backgroundColor(COLOR_PRIMARY)
              .borderRadius(8)
          }
          Text(combo.howto).fontSize(12).fontColor(COLOR_TEXT_SEC)
        }
      }
    }, (_: ComboEntry, idx: number) => `combo_${idx}`)
  }
}

3.3 Flex + ForEach 实现流式网格布局

在本应用中,选项的展示采用了 Flex 容器配合 FlexWrap.Wrap 模式,实现了流式网格布局。这是鸿蒙声明式UI中处理多选项选择的典型模式:

Flex({ wrap: FlexWrap.Wrap, justifyContent: FlexAlign.Start }) {
  ForEach(items, (item: string) => {
    Text(item)
      .padding({ left: 14, right: 14, top: 8, bottom: 8 })
      .borderRadius(16)
      .border({ width: 1, color: selected === item ? COLOR_PRIMARY : COLOR_BORDER })
      .margin({ right: 8, bottom: 8 })
      .onClick(() => { onClick(item) })
  })
}

这种布局的优势在于:

  • 自动换行:当屏幕宽度不足以容纳所有选项时,自动折行显示
  • 等距间距:通过 marginrightbottom 实现统一间距
  • 自适应:无需手动计算位置,Flex布局引擎自动处理

3.4 Scroll + layoutWeight 实现可滚动结果区

当AI生成结果后,如果结果区域超出屏幕高度,通过 Scroll 包裹和 layoutWeight(1) 权重分配,实现优雅的可滚动体验:

if (this.currentData !== null) {
  Scroll() {
    Column() {
      this.buildResultCard(this.currentData)
    }
    .padding({ bottom: 20 })
  }
  .layoutWeight(1)    // ⭐ 占据剩余空间
  .scrollBar(BarState.Off)  // 隐藏滚动条
}

layoutWeight(1) 让 Scroll 自动填充父容器剩余的所有垂直空间,配合 BarState.Off 隐藏滚动条,使UI保持清爽简洁。

四、AI应用亮点分析

4.1 12种组合 × 3套方案 = 36种早餐选择

极简早餐搭配的核心AI能力体现在其12种组合(3时间×4偏好) 的知识覆盖上。每种组合都预置了3套完整的早餐方案,总共有36种不同的早餐推荐,覆盖了从"5分钟快手"到"15分钟高蛋白"的广泛场景。

时间 快手 健康 高蛋白 低碳水
5分钟 牛油果吐司+牛奶(320kcal) 燕麦牛奶粥(260kcal) 蛋白奶昔+全麦面包(380kcal) 牛油果培根蛋杯(330kcal)
10分钟 火腿芝士三明治(380kcal) 蔬菜鸡蛋饼(320kcal) 鸡胸肉全麦卷(420kcal) 西葫芦蛋饼(280kcal)
15分钟 什锦炒饭(420kcal) 全麦意面沙拉(380kcal) 牛肉蔬菜卷(460kcal) 花椰菜炒饭(260kcal)

4.2 精确热量计算与营养可视化

每套方案都标注了精确的热量值(kcal),从最低的250kcal(奇亚籽布丁)到最高的480kcal(三文鱼蛋炒饭),覆盖了从减脂到增肌的全面需求。热量以胶囊标签形式展示在卡片上,视觉上醒目且信息层级清晰。

4.3 可执行的做法要点

与传统菜谱不同,AI生成的做法要点经过了"极简化"处理,每条不超过30个字,以"动作+食材+工具"的极简句式呈现。例如:

  • 全麦面包烤1分钟,抹牛油果泥,配一杯热牛奶
  • 即食燕麦加牛奶微波炉2分钟,撒坚果碎

这种做法要点的设计哲学是:不需要打开任何一个APP或网页,扫一眼就知道怎么做

五、关键技术挑战与解决方案

5.1 挑战一:AI响应延迟的交互设计

问题:AI生成需要时间(模拟1500ms),用户需要明确的等待反馈。

解决方案:引入 @State isLoading 状态变量,在生成过程中显示loading提示:

if (this.isLoading) {
  Row() {
    Text('🍳 正在搭配营养早餐……')
      .fontSize(13)
      .fontColor(COLOR_TEXT_SEC)
      .padding(12)
  }
  .width('100%')
  .padding({ left: 16 })
}

setTimeout 模拟AI延迟,同时用 isLoading = true 禁用按钮防重复点击,用自然语言提示"正在搭配营养早餐"而非枯燥的加载动画,更符合生活服务类APP调性。

5.2 挑战二:状态重置的一致性

问题:用户点击"重置"时需要恢复所有状态到初始值,涉及多个 @State 变量的同步。

解决方案:在 onReset() 方法中统一清理所有状态:

private onReset(): void {
  this.selectedTime = ''
  this.selectedPreference = ''
  this.currentData = null
  this.messages = []
  this.messages.push(new BCMessage(BCMessageRole.ASSISTANT, BC_WELCOME, null))
}

这里需要注意两个细节:一是 currentData 必须置为 null 而非空对象,因为条件渲染判断的是 null 而非空数组;二是重置后要重新推送欢迎消息,维持消息队列的一致性。

5.3 挑战三:颜色主题的统一管理

问题:页面中使用了多种颜色,散落在代码中会导致维护困难。

解决方案:在页面顶部定义颜色常量:

const COLOR_BG = '#F7FEE7'        // 柔和淡绿背景
const COLOR_CARD = '#FFFFFF'       // 纯白卡片
const COLOR_TEXT = '#1E293B'       // 深色正文
const COLOR_TEXT_SEC = '#64748B'   // 灰色辅助文字
const COLOR_BORDER = '#D9F99D'    // 浅绿边框
const COLOR_PRIMARY = '#84CC16'    // 主色调(活力绿)
const COLOR_SELECTED_BG = '#ECFCCB' // 选中态背景

这种常量化管理方案在鸿蒙开发中尤为有效,因为ArkTS不支持CSS变量,通过顶层常量可以实现类似主题定制的效果。

六、用户体验设计

6.1 色彩心理学应用

主色调选用 #84CC16 活力的草绿色,传递出生机、健康、自然的品牌调性。背景色 #F7FEE7 的极淡绿色,长时间使用也不会产生视觉疲劳,非常适合早餐场景"清晨使用"的特点。

6.2 交互流程极简设计

整个应用的交互路径只有三步:选择 → 选择 → 生成,路径长度仅2步,符合"极简"的产品定位。

6.3 信息层级设计

结果卡片的信息层级遵循 F型布局

  • 第一层:序号圆标(快速定位)
  • 第二层:早餐名称(粗体,一目了然)
  • 第三层:热量标签(胶囊样式,视觉突出)
  • 第四层:做法要点(灰色小字,按需阅读)

七、总结

极简早餐搭配虽然是一个功能聚焦的小型AI应用,但它充分展现了鸿蒙ArkTS声明式UI框架在快速开发、响应式状态管理、组件复用等方面的强大能力。通过 @State 双条件联动、@Builder 参数化组件、Flex + ForEach 流式布局等核心技术实践,我们不仅构建了一个用户体验优秀的AI产品,也验证了HarmonyOS在生活服务类应用开发中的技术可行性。

从AI角度来看,36种早餐方案的预置知识库虽然并非真正的"AI生成",但通过结构化数据设计模拟了AI的智能推荐效果,为后续接入大模型API奠定了良好的架构基础。未来可以进一步接入真正的AI模型,实现基于个人口味偏好、冰箱剩余食材的动态推荐,让"极简早餐搭配"真正成为每个家庭的智能营养管家。

Logo

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

更多推荐