鸿蒙 ArkTS 实战:Family Truth Cards 从家庭真心话卡片到成绩记录完整解析

前言

Family Truth Cards 是一个面向 家庭真心话卡片 的鸿蒙 ArkTS 单页应用。项目代码集中在 Index.ets,通过 @State 管理记录列表、输入内容、声音开关和状态提示,并用 ForEach 把每一轮记录渲染为可勾选列表。

这篇文章直接基于项目源码展开,不写空泛介绍,重点分析它的数据模型、默认记录、统计函数、表单提交、列表刷新和后续扩展方式。对于学习 ArkTS 单页应用的人来说,这类项目很适合用来理解状态驱动 UI 的基本路径。

轻量小游戏或训练工具不一定先做复杂玩法。先把记录、统计、反馈和列表交互搭起来,后续接入真正的游戏逻辑会更稳。

在这里插入图片描述

配图展示的是开发者生态入口,发布时也可以替换成应用运行截图。本文关注的结构是:顶部指标、功能标签、声音开关、录入表单和记录列表。

一、项目定位与源码入口

1.1 应用定位

面向家庭互动场景,用问题分类、随机抽取、跳过规则和收藏问题管理每轮卡片体验。

当前页面不是复杂多页应用,而是一个清晰的单页面闭环:用户看到默认记录,输入新的轮次信息,点击按钮保存,再通过列表勾选需要关注的记录。

1.2 源码入口

核心文件位于 entry/src/main/ets/pages/Index.ets,入口组件使用 @Entry@Component 标记。

@Entry
@Component
struct Index {
  build() {
    Scroll() {
      Column({ space: 14 }) {
        Text('Family Truth Cards')
      }
    }
  }
}
区域作用对应能力
标题呈现应用名称Family Truth Cards
统计卡片展示 Cards 与 Selected汇总与计数
标签区展示玩法模块Question category, Random draw, Skip rule, Saved question
表单新增记录TextInputButton
列表管理记录状态ForEachToggle

二、数据模型设计

2.1 记录接口

项目使用 GameRound 描述每一条游戏记录。

interface GameRound {
  title: string;
  score: number;
  note: string;
  active: boolean;
}

这个接口非常适合成绩类应用。title 表示轮次或关卡,score 保存 卡片数量note 用来保存补充描述,active 则控制是否被选中。

2.2 字段语义

字段类型在本项目中的含义
titlestring轮次、关卡或分类名称
scorenumber卡片数量
notestring结果说明、提示状态或扩展备注
activeboolean是否作为重点记录

数据模型稳定 是这类项目的关键。后续即使增加真实玩法,也可以继续把最终结果写回同一个记录结构。

三、默认数据与业务语义

3.1 默认记录

页面初始化时已经准备两条业务记录。

@State rounds: GameRound[] = [
    { title: 'Warmup questions', score: 6, note: 'Skip rule 2', active: false },
    { title: 'Memory questions', score: 4, note: 'Saved favorite', active: false }
];
默认标题数值备注是否选中
Warmup questions6Skip rule 2false
Memory questions4Saved favoritefalse

3.2 默认数据的价值

默认数据让用户首次进入页面时就能理解这个应用要记录什么。比如 Warmup questionsMemory questions 分别对应不同训练或玩法场景,备注字段则补充了结果细节。

  1. 空列表会降低理解效率。
  2. 示例记录可以说明输入格式。
  3. 顶部统计从首次打开就有可读数值。

四、页面状态管理

4.1 状态字段

页面使用 @State 保存列表、表单、开关和提示文本。

@State rounds: GameRound[] = [];
@State titleText: string = '';
@State scoreText: string = '';
@State noteText: string = '';
@State soundOn: boolean = true;
@State status: string = 'Game ready';

4.2 状态流转

状态触发动作结果
rounds新增或勾选记录列表和统计刷新
titleText输入轮次名称提交时写入 title
scoreText输入数值转换为 score
noteText输入备注写入 note
soundOn切换声音开关保存声音偏好
status提交表单展示错误或成功信息

ArkTS 的声明式体验重点在于状态变化。只要状态设计清楚,UI 更新就能自然跟随数据变化。

五、统计函数拆解

5.1 累计 Cards

顶部左侧指标来自 totalScore()

private totalScore(): number {
  let total = 0;
  this.rounds.forEach((item: GameRound) => {
    total += item.score;
  });
  return total;
}

5.2 计算选中数量

右侧 Selected 来自 selectedCount()

private selectedCount(): number {
  let count = 0;
  this.rounds.forEach((item: GameRound) => {
    if (item.active) {
      count++;
    }
  });
  return count;
}

这两个函数都只读列表状态,不修改任何数据,因此适合作为 UI 层的派生计算。

六、顶部指标卡片实现

6.1 卡片代码

顶部区域使用两个 Column 并排展示核心指标。

Row({ space: 10 }) {
  Column({ space: 4 }) {
    Text('Cards').fontSize(13).fontColor('#475569')
    Text(String(this.totalScore())).fontSize(24).fontWeight(FontWeight.Bold).fontColor('#DC2626')
  }.layoutWeight(1).padding(14).backgroundColor('#FEE2E2').borderRadius(8)
  Column({ space: 4 }) {
    Text('Selected').fontSize(13).fontColor('#475569')
    Text(this.selectedCount() + '/' + this.rounds.length).fontSize(24).fontWeight(FontWeight.Bold).fontColor('#1D4ED8')
  }.layoutWeight(1).padding(14).backgroundColor('#DBEAFE').borderRadius(8)
}

6.2 指标解释

指标数据来源产品含义
Cards所有记录的 score 汇总衡量整体表现
Selectedactive 为 true 的记录数量标记当前关注记录
总数rounds.length展示记录规模

对于 家庭真心话卡片卡片数量 是最重要的结果数据,因此放在左侧主卡片。

七、功能标签区域

7.1 标签渲染

页面用四个短标签概括玩法能力。

Column({ space: 8 }) {
  Row({ space: 8 }) {
    Text('Question category').layoutWeight(1).fontSize(13).textAlign(TextAlign.Center)
    Text('Random draw').layoutWeight(1).fontSize(13).textAlign(TextAlign.Center)
  }
  Row({ space: 8 }) {
    Text('Skip rule').layoutWeight(1).fontSize(13).textAlign(TextAlign.Center)
    Text('Saved question').layoutWeight(1).fontSize(13).textAlign(TextAlign.Center)
  }
}

7.2 标签含义

序号标签说明
1Question category主玩法入口
2Random draw交互过程
3Skip rule结果反馈
4Saved question沉淀能力

功能标签的好处是信息密度高,不需要额外说明文字,也能让用户迅速理解页面能力。

八、声音开关与配置入口

8.1 开关代码

页面提供 Sound 开关,状态保存在 soundOn 中。

Row() {
  Text('Sound').fontSize(16).fontColor('#374151')
  Blank()
  Toggle({ type: ToggleType.Switch, isOn: this.soundOn })
    .onChange((checked: boolean) => this.soundOn = checked)
}

8.2 扩展方向

在当前版本中,soundOn 还没有接入音频系统,但它已经占好了配置位置。后续可以根据它控制按钮音效、答题反馈音、成功提示音或错误提醒音。

九、表单录入与校验

9.1 输入区结构

表单由名称、数值、备注和按钮组成。

Column({ space: 10 }) {
  TextInput({ placeholder: 'Round name', text: this.titleText })
    .onChange((value: string) => this.titleText = value)
  TextInput({ placeholder: 'Score', text: this.scoreText })
    .type(InputType.Number)
    .onChange((value: string) => this.scoreText = value)
  TextInput({ placeholder: 'Note', text: this.noteText })
    .onChange((value: string) => this.noteText = value)
  Button('Add score').height(42).width('100%').onClick(() => this.addRound())
}

9.2 校验规则

提交时会先检查名称和数值。名称不能为空,分数必须能转换成有效数字。

const score = Number(this.scoreText);
if (this.titleText.trim().length === 0 || !Number.isFinite(score)) {
  this.status = 'Enter round and valid score';
  return;
}

这个校验足够直接,能避免空标题和非法分数进入列表。

十、新增记录逻辑

10.1 保存方法

新增记录由 addRound() 完成。

private addRound(): void {
  const score = Number(this.scoreText);
  if (this.titleText.trim().length === 0 || !Number.isFinite(score)) {
    this.status = 'Enter round and valid score';
    return;
  }
  this.rounds = [{
    title: this.titleText,
    score: Math.round(score),
    note: this.noteText.length > 0 ? this.noteText : 'No note yet',
    active: false
  }, ...this.rounds];
  this.titleText = '';
  this.scoreText = '';
  this.noteText = '';
  this.status = 'Round saved';
}

10.2 头部插入

新记录会插入到数组头部。这样用户提交后,最新数据立即出现在第一条,反馈路径很短。

十一、列表渲染与选中态

11.1 ForEach 渲染

列表渲染使用 ForEach 遍历 rounds

ForEach(this.rounds, (item: GameRound, index: number) => {
  Row() {
    Toggle({ type: ToggleType.Checkbox, isOn: item.active })
      .onChange(() => this.toggleActive(index))
    Column({ space: 6 }) {
      Text(item.title).fontSize(18).fontWeight(FontWeight.Bold)
      Text(item.note).fontSize(14).fontColor('#475569')
    }.layoutWeight(1).margin({ left: 8 })
    Text(String(item.score)).fontSize(18).fontWeight(FontWeight.Bold).fontColor('#DC2626')
  }.padding(14).backgroundColor(item.active ? '#DCFCE7' : '#FFFFFF').borderRadius(8)
})

11.2 勾选更新

切换勾选时,先修改当前项,再用展开语法生成新数组引用。

private toggleActive(index: number): void {
  this.rounds[index].active = !this.rounds[index].active;
  this.rounds = [...this.rounds];
}

这个写法保证列表 UI 能感知状态变化。选中的记录会使用 #DCFCE7 背景色,视觉反馈明确。

十二、布局与视觉层次

12.1 页面容器

外层使用 Scroll,内部使用 Column

Scroll() {
  Column({ space: 14 }) {
    Text('Family Truth Cards')
    // stats
    // tags
    // sound switch
    // form
    // list
  }.padding(18).width('100%')
}.height('100%').backgroundColor('#F8FAFC')

12.2 配色表

颜色使用位置作用
#F8FAFC页面背景保持浅色基底
#DC2626主指标数值强调成绩
#1D4ED8Selected 数值强调选择状态
#DCFCE7选中列表项表达活跃状态
#F1F5F9表单背景区分输入区域

十三、运行验证流程

13.1 手工验证路径

可以按以下流程验证:

  1. 打开页面,确认标题是 Family Truth Cards
  2. 查看默认两条记录是否出现。
  3. 点击 Add score 且不输入内容,确认提示为 Enter round and valid score
  4. 输入 Daily round99 和备注,再点击保存。
  5. 勾选新记录,确认背景变绿且 Selected 数量增加。
this.titleText = 'Daily round';
this.scoreText = '99';
this.noteText = 'Manual record';
this.addRound();

// 预期:status 更新为 Round saved
// 预期:新记录位于列表第一项

13.2 验证要点

验证点预期结果
空标题提交显示错误提示
合法提交新记录插入列表顶部
数值输入保存为整数 score
勾选记录active 取反
顶部统计跟随列表变化

十四、面向真实玩法的扩展

14.1 业务扩展

后续可以加入问题库、随机抽卡动画、跳过次数限制、收藏列表和多人轮换。

14.2 工程扩展

后续扩展时,可以保持当前页面的状态结构不变,只把真实玩法结果接入 scorenote

interface PlayResult {
  roundTitle: string;
  finalScore: number;
  summary: string;
}

function mapResultToRound(result: PlayResult): GameRound {
  return {
    title: result.roundTitle,
    score: result.finalScore,
    note: result.summary,
    active: false
  };
}

这样可以把玩法层和记录层分开,避免页面代码随着功能增加而失控。

十五、工程复盘

15.1 当前实现的优点

  • 数据结构简单,字段语义清楚。
  • 统计函数只依赖列表数据,逻辑可预测。
  • 表单校验直接,错误提示明确。
  • 列表更新使用新数组引用,刷新路径稳定。
  • 功能标签贴合 家庭真心话卡片 的业务方向。

15.2 可复用经验

这类结构可以复用到答题、训练、学习、聚会游戏、儿童教育和轻量工具中。只要业务结果可以表达为“标题 + 数值 + 备注 + 状态”,就能套入相同的记录管理骨架。

总结

Family Truth Cards 展示了一个完整的鸿蒙 ArkTS 小应用骨架:用 GameRound 定义记录,用 rounds 保存列表,用 totalScore()selectedCount() 输出统计结果,用 addRound() 完成表单提交,再用 ForEachToggle 完成记录展示与选中状态更新。

它的代码不复杂,但工程链路完整。对于 家庭真心话卡片 这种玩法来说,当前版本已经完成了成绩记录层;后续只需要逐步补齐真实玩法,就能从原型平滑走向可用产品。

补充说明:当前页面把业务状态集中在组件内,适合小型训练工具快速迭代。
补充说明:记录列表采用头部插入,能让用户提交后立即看到最新结果。
补充说明:备注字段保留了足够弹性,可以承载提示、收藏、错误次数或扩展状态。
补充说明:统计卡片和列表项共享同一份数据,减少了重复状态带来的不一致风险。

补充说明:当前页面把业务状态集中在组件内,适合小型训练工具快速迭代。
补充说明:记录列表采用头部插入,能让用户提交后立即看到最新结果。
补充说明:备注字段保留了足够弹性,可以承载提示、收藏、错误次数或扩展状态。
补充说明:统计卡片和列表项共享同一份数据,减少了重复状态带来的不一致风险。


相关资源:

更多推荐