欢迎光临
我们一直在努力

鸿蒙 Next 老年人防骗训练 App 开发实战:适老化设计 + 情景训练 + 系列总结

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述

鸿蒙 Next 老年人防骗训练 App 开发实战:适老化设计 + 情景训练 + 系列总结

作者:duluo SDK 版本:HarmonyOS API 24 (Next) 开发工具:DevEco Studio 语言框架:ArkTS + ArkUI 字数:约 12000 字


目录

  • 引言
  • 产品概念与需求分析
  • 适老化 UI 设计原则
  • 三 Tab 架构总览
  • 情景训练模块:从需求到实现
  • 防骗知识库:静态内容展示
  • 紧急求助页面:大按钮设计
  • 学习进度追踪与持久化
  • 编译错误回顾
  • 五款 App 系列总结
  • 给 HarmonyOS 新手的建议

  • 1. 引言

    1.1 老年人防骗的社会意义

    根据中国公安部发布的数据,2023 年全国电信网络诈骗案件中,60 岁以上的老年受害人占比持续上升。常见的诈骗手段包括冒充公检法、保健品推销、投资理财骗局、亲情诈骗等。老年人群体由于信息获取渠道有限、对新技术不熟悉、且往往独居缺乏沟通,成为了诈骗分子的重点目标。

    "老年人防骗训练"App 的设计初衷,是通过情景模拟训练帮助老年人提高防骗意识。它不是一款娱乐产品,而是一款具有社会价值的公益工具。

    1.2 本 App 的技术定位

    与前四款 App 相比,本 App 在技术上引入了新的维度——适老化设计:

    维度前四款防骗训练
    目标用户 通用 老年人(适老化)
    字体大小 14-18sp 18-24sp
    按钮尺寸 44px 56px+
    交互逻辑 灵活操作 简单明确
    内容密度 中等 低密度、高可读性
    数据模型 用户数据 静态 + 进度

    1.3 系列回顾

    这是本系列的第五款应用。前四款分别是:

  • 沉浸式白噪音 — 多媒体 + 动画
  • 时间胶囊 — 数据持久化 + Builder 约束
  • 冰箱剩菜大作战 — Tab 架构 + 游戏化
  • 尴尬粉碎机 — 静态数据 + 仪式感交互
  • 每款 App 都在前一基础上引入新的技术维度。本 App 作为收官之作,将重点放在适老化设计和模式复用上,同时对所有五款 App 的架构模式做系统性总结。


    2. 产品概念与需求分析

    2.1 核心功能需求

    用户故事 1:老人希望通过真实案例学习识别骗局
    用户故事 2:老人需要大字大图的界面,方便阅读和操作
    用户故事 3:老人希望能看到自己的学习进度
    用户故事 4:老人遇到可疑情况时,需要快速查到求助电话

    功能清单:
    ├── F1: 情景判断题(12 个真实诈骗场景)
    ├── F2: 答题反馈(正确/错误 + 详细解析)
    ├── F3: 防骗知识手册(6 条防骗口诀)
    ├── F4: 紧急求助电话(110/96110/12377/12315)
    ├── F5: 学习进度追踪(得分 + 完成度)
    └── F6: 数据持久化(进度不丢失)

    2.2 适老化设计原则

    在设计过程中,我们遵循了以下适老化设计原则:

    原则说明实现方式
    大字原则 所有字体 ≥ 16sp 正文 18sp,标题 24sp
    高对比度 文字与背景对比鲜明 深色文字 #212121 配白色背景
    大按钮 触摸区域 ≥ 48x48px 按钮 56px 高,130px 宽
    简单导航 减少层级,所有内容三 Tab 内直达 无二级页面嵌套
    明确反馈 每次操作有清晰结果 正确/错误 + 解析弹窗
    低信息密度 每屏展示内容精简 大间距、充足留白

    2.3 信息架构

    防骗训练营
    ├── Tab 0: 情景训练
    │ ├── 进度概览(已完成 N/12 + 圆点进度条)
    │ ├── 12 个情景条目(带状态图标)
    │ └── 情景详情弹窗
    │ ├── 场景描述(大字体阅读)
    │ ├── 判断按钮(安全/骗局)
    │ └── 结果弹窗(解析 + 得分)

    ├── Tab 1: 防骗知识
    │ ├── 6 条防骗口诀(八个凡是/六个一律/…)
    │ └── 知识详情弹窗(完整内容)

    └── Tab 2: 紧急求助
    ├── 4 个紧急号码大按钮
    └── 应急处理指南


    3. 适老化 UI 设计原则

    3.1 大字体系

    常规 App 的字体通常在 14-16sp,而我们针对老年人将字体整体放大:

    // 普通 App 的字体
    Text('阅读以下情景,判断是不是骗局')
    .fontSize(14) // 常规大小

    // 适老化字体
    Text('阅读以下情景,判断是不是骗局')
    .fontSize(16) // 增大 2sp

    // 标题
    Text('情景判断题')
    .fontSize(22) // 大标题

    // 情景描述
    Text(scenario.description)
    .fontSize(18)
    .lineHeight(30) // 1.67 倍行距

    行距设计:常规行距为 1.2-1.4 倍,我们设置为 1.67 倍(lineHeight: 30,字号 18),降低阅读疲劳。

    3.2 高对比度配色

    const ALL_COLORS: ColorScheme = {
    primary: '#1565C0', // 深蓝色主色
    success: '#2E7D32', // 深绿色(正确)
    danger: '#C62828', // 深红色(错误/危险)
    text: '#212121', // 近黑色文字(最高对比度)
    cardBg: '#FFFFFF', // 纯白卡片背景
    // …
    }

    对比度检查:

    • 正文 #212121 配白底 → 对比度 14.5:1(远超 WCAG AAA 标准 7:1)
    • 主色 #1565C0 配白底 → 对比度 7.8:1(满足 AAA 标准)

    3.3 大按钮设计

    // 判断按钮:56px 高,130px 宽
    Column() {
    Text('\\u{2705} 安全')
    .fontSize(20)
    .fontColor(Color.White)
    .fontWeight(FontWeight.Bold)
    }
    .width(130)
    .height(56)
    .backgroundColor(ALL_COLORS.success)
    .borderRadius(16)

    56px 的高度远超标准 44px 的最小触摸目标,确保老年人即使手部颤抖也能准确点击。

    3.4 紧急号码的极致放大

    在紧急求助页面,电话号码使用 40sp 的超大字体:

    Text('110')
    .fontSize(40) // 超大
    .fontColor(Color.White)
    .fontWeight(FontWeight.Bold)

    整个号码卡片高 100px,确保在紧急情况下老人能够一眼看到并拨打。


    4. 三 Tab 架构总览

    4.1 Tab 配置

    @Builder
    buildTabBar() {
    Row() {
    this.buildTabItem(0, '\\u{1F9E0}', '情景训练')
    this.buildTabItem(1, '\\u{1F4DA}', '防骗知识')
    this.buildTabItem(2, '\\u{1F6A8}', '紧急求助')
    }
    .height(64) // 比常规 56px 更高
    }

    Tab 栏高度增加到 64px(前作均为 56px),提供更大的触摸目标。

    4.2 Tab 内容的三个 Builder

    @Builder
    buildTabContent() {
    if (this.activeTab === 0) {
    this.buildTrainPage()
    } else if (this.activeTab === 1) {
    this.buildKnowledgePage()
    } else {
    this.buildEmergencyPage()
    }
    }

    三个 Tab 的内容都是 Scroll 内嵌 Column,适合大量文本阅读。

    4.3 标题栏中的进度展示

    if (this.activeTab === 0) {
    Column() {
    Text(this.progress.highScore.toString())
    .fontSize(18)
    .fontColor(ALL_COLORS.accent)
    .fontWeight(FontWeight.Bold)
    Text('最高分')
    .fontSize(11)
    .fontColor(ALL_COLORS.textHint)
    }
    }

    在标题栏右上角显示"最高分",让老人随时看到自己的最佳成绩,形成正向激励。


    5. 情景训练模块:从需求到实现

    5.1 数据模型

    interface ScamScenario {
    id: number;
    title: string; // 情景标题
    description: string; // 情景描述(200-300 字)
    isScam: boolean; // 是否是骗局(所有情景都是 true)
    explanation: string; // 解析
    category: string; // 分类(电信诈骗/保健品诈骗/…)
    }

    设计决策:12 个情景的 isScam 全部为 true。为什么不加入"安全"的情景?

    原因如下:

  • 教育目的:App 的目标是教会老人识别骗局,不是测试智力
  • 降低认知负担:老人不需要区分"这个是不是骗局",只需学习"骗子有哪些套路"
  • 避免混淆:如果有些是安全有些是骗局,老人可能记住"误导性案例"
  • 正向强化:每次都判断为骗局并答对,建立自信心
  • 5.2 情景列表设计

    ForEach(SCENARIOS, (scenario: ScamScenario) => {
    Column() {
    Row() {
    Text(this.getScenarioIcon(scenario.id)) // ❓/✅/❌
    Column() {
    Text(scenario.title).fontSize(18)
    Text(scenario.category) // 带颜色标签
    }
    Text('\\u{276F}') // 右箭头
    }
    }
    .onClick(() => { this.openScenario(scenario); })
    })

    每个情景条目包含三个元素:

    • 状态图标:未答 ❓、正确 ✅、错误 ❌
    • 标题 + 分类标签:分类使用不同颜色(电信诈骗=红、保健品=紫、投资=橙等)
    • 右箭头:指示可点击

    5.3 圆点进度条

    Row() {
    ForEach(SCENARIOS, (scenario: ScamScenario) => {
    Column() {
    Circle()
    .width(22).height(22)
    .fill(this.getScenarioStatus(scenario.id))
    }
    })
    }

    12 个圆点代表 12 道题:

    • 灰色 #E0E0E0 = 未作答
    • 绿色 #2E7D32 = 回答正确
    • 红色 #C62828 = 回答错误

    这是一种一目了然的进度可视化,老人不需要读文字就能了解自己的完成情况。

    5.4 情景详情弹窗

    弹窗包含三个部分:

    上部:标题 + 分类

    Row() {
    Text(this.getScenarioIcon(this.selectedScenario!.id))
    Text(this.selectedScenario.title)
    }
    Text(this.selectedScenario.category + ' · 判断题')

    中部:情景描述

    Scroll() {
    Text(this.selectedScenario.description)
    .fontSize(18).lineHeight(30)
    }
    .height(160)

    描述使用 18sp 字体 + 30sp 行距,适合老人阅读。

    下部:判断按钮

    Row() {
    Column() { Text('✅ 安全') } // 绿色
    .width(130).height(56).backgroundColor(success)
    Column() { Text('⚠️ 骗局') } // 红色
    .width(130).height(56).backgroundColor(danger)
    }

    两个大按钮并列,老人只需在二者之间选择。按钮颜色与语义一致(绿=安全,红=危险)。

    5.5 答题逻辑

    answerScenario(scenarioId: number, answerIsScam: boolean): void {
    let scenario = SCENARIOS.find(s => s.id === scenarioId);
    this.lastAnswerCorrect = (answerIsScam === scenario.isScam);

    if (this.progress.completedIds.indexOf(scenarioId) < 0) {
    this.progress.completedIds = this.progress.completedIds.concat([scenarioId]);
    if (this.lastAnswerCorrect) this.progress.correctCount++;
    this.progress.totalCount++;
    let pct = Math.round(this.progress.correctCount / this.progress.totalCount * 100);
    if (pct > this.progress.highScore) this.progress.highScore = pct;
    this.progress = this.copyProgress(this.progress);
    this.saveProgress();
    }
    this.showScenarioDetail = false;
    this.showResult = true;
    }

    积分规则:

    • 每题只有首次作答计分(后续进入查看不会重复计分)
    • 答对 +1 正确数
    • 最高分取所有答题轮次中的最高正确率

    5.6 结果弹窗

    答题后弹出结果页,包含正确答案和详细解析:

    Text(this.lastAnswerCorrect ? '回答正确!' : '回答错误')
    Text('正确答案:这是骗局')
    Text('解析')
    Scroll() { Text(scenario.explanation) }
    Text('进度:5 / 12')
    Text('得分:4 / 5')

    解析部分使用 Scroll 容器,可以滚动阅读全文。每条解析约 100-150 字,用通俗语言解释为什么这是骗局,以及正确的应对方式。


    6. 防骗知识库:静态内容展示

    6.1 数据模型

    interface KnowledgeItem {
    id: number;
    title: string; // 标题
    content: string; // 正文内容
    icon: string; // Emoji 图标
    color: string; // 主题色
    }

    6.2 六条防骗口诀

    条目图标颜色核心内容
    八个凡是 ⚠️ 8 种"凡是"都是诈骗
    六个一律 🚫 6 种情况一律挂断/删除
    三不一多 📚 绿 不点/不信/不透露/多核实
    保健品骗局 💊 5 大特征识别保健品诈骗
    投资理财防骗 💰 5 条理财防骗原则
    遇骗应急处理 🚨 被骗后的 5 步应急措施

    6.3 内容展示

    知识条目使用卡片列表展示,点击进入详情弹窗:

    ForEach(KNOWLEDGE_LIST, (item: KnowledgeItem) => {
    Column() {
    Row() {
    Text(item.icon).fontSize(32)
    Column() {
    Text(item.title).fontSize(20).fontWeight(FontWeight.Bold)
    Text('点击查看详细内容').fontSize(14)
    }
    Text('\\u{276F}')
    }
    }
    .onClick(() => {
    this.selectedKnowledge = item;
    this.showKnowledgeDetail = true;
    })
    })

    适老化细节:

    • 标题使用 20sp,比常规大 4sp
    • 提示文字使用 14sp,虽然略小但不是关键信息
    • 整行可点击,触摸区域大

    7. 紧急求助页面:大按钮设计

    7.1 四个紧急号码

    // 110 报警
    Column() {
    Text('110').fontSize(40).fontColor(Color.White).fontWeight(FontWeight.Bold)
    Text('报警电话').fontSize(16).fontColor(Color.White)
    }
    .width('85%').height(100)
    .backgroundColor(ALL_COLORS.danger) // 红色
    .borderRadius(20)

    // 96110 反诈专线(橙色)
    // 12377 网络违法举报(蓝色)
    // 12315 消费者投诉(绿色)

    号码卡片 100px 高,使用 40sp 超大字体,不同颜色区分。

    7.2 遇骗应急处理

    Column() {
    Text('如果不幸被骗:')
    Text('1. 第一时间拨打110报警')
    Text('2. 联系银行冻结账户')
    Text('3. 保存聊天记录和转账凭证')
    Text('4. 不要因羞愧而隐瞒')
    Text('5. 越早报警,追回希望越大')
    }
    .fontSize(16)
    .lineHeight(26)

    应急指南采用编号列表形式,清晰易读。特别加入"不要因羞愧而隐瞒"这一条——很多老人被骗后因为觉得丢人不愿声张,错过了最佳报案时间。


    8. 学习进度追踪与持久化

    8.1 进度数据模型

    interface TrainProgress {
    completedIds: number[]; // 已完成的题目 ID 列表
    correctCount: number; // 答对数量
    totalCount: number; // 总答题数
    highScore: number; // 最高正确率 (0-100)
    }

    8.2 数据持久化

    async loadProgress(): Promise<void> {
    let context = getContext(this);
    this.dataPreferences = await preferences.getPreferences(context, 'scam_train_db');
    let val = await this.dataPreferences.get(STORAGE_KEY_PROGRESS, '');
    if (val !== '') {
    let data = JSON.parse(val as string) as TrainProgress;
    if (data) this.progress = data;
    }
    }

    async saveProgress(): Promise<void> {
    if (this.dataPreferences) {
    await this.dataPreferences.put(STORAGE_KEY_PROGRESS, JSON.stringify(this.progress));
    await this.dataPreferences.flush();
    }
    }

    单键值存储:只存储 TrainProgress 一个对象,情景数据和知识数据都是静态常量。

    8.3 进度的可视化

    进度通过三种方式可视化:

  • 标题栏数字:右上角显示"最高分"
  • 圆点进度条:12 个带颜色圆点
  • 文字提示:已完成 N / 12 题
  • Text('已完成 ' + this.progress.completedIds.length + ' / ' + SCENARIOS.length + ' 题')

    三种可视化方式适应不同的信息获取习惯——喜欢看数字的看数字,喜欢看图形的看圆点。

    8.4 防止重复计分

    if (this.progress.completedIds.indexOf(scenarioId) < 0) {
    // 首次作答才计分
    this.progress.completedIds = this.progress.completedIds.concat([scenarioId]);
    // 更新分数…
    }

    indexOf 检查:如果 ID 已在 completedIds 中,说明是重复查看,不重复计分。这确保了分数反映的是真实的答题次数。


    9. 编译错误回顾

    9.1 本 App 的错误

    本次编译共出现 12 个错误,类型分布如下:

    类型数量占比
    对象字面量无类型 1 8%
    @Builder 中 let 声明 6 50%
    API 不存在(flexWrap) 1 8%
    样式错误(TextStyle.NONE) 1 8%
    双点号(…backgroundColor) 1 8%
    展开运算符 1 8%
    空值安全 1 8%

    9.2 典型错误修复

    错误 1:flexWrap 不存在

    // ❌ Row 组件没有 flexWrap 属性
    Row() { }.flexWrap(FlexWrap.Wrap)

    // ✅ 移除即可,Row 默认不换行
    Row() { }

    错误 2:TextStyle.NONE 不存在

    // ❌ TextStyle 枚举没有 NONE 值
    Text(' ', { style: TextStyle.NONE })

    // ✅ 直接传文本,省略 style 参数
    Text(' ')

    错误 3:双点号 ..backgroundColor

    // ❌ 输入错误
    ..backgroundColor('#43A047')

    // ✅ 正确
    .backgroundColor('#43A047')

    9.3 Builder 语法约束的深度理解

    在五款 App 的开发中,@Builder 的语法约束是遇到最多的错误类型。这里做一次系统性总结:

    @Builder 中可以写什么?

    语法是否允许示例
    UI 组件声明 Column(), Text(), Row()
    属性链式调用 .fontSize(), .width()
    if/else 条件渲染 if (x) { Text() }
    ForEach 循环 ForEach(list, item => { Text() })
    调用其他 @Builder this.buildXxx()
    let 变量声明 let x = getData()
    return 语句 if (!x) return;
    函数调用(非Builder) someFunction()
    闭包参数 @Builder fn(label: string, content: () => void)

    根本原因:@Builder 方法在编译时会被 ArkUI 编译器做特殊处理。它不是一个普通的函数,而是一个UI 声明块。编译器会分析 Builder 中的组件树,生成高效的渲染指令。如果在 Builder 中混入命令式逻辑,编译器无法正确分析组件树。

    实践建议:

    • 如果一个 @Builder 方法超过 50 行,考虑拆分为多个子 Builder
    • 如果一个 @Builder 方法中有超过 3 个 if/else 分支,将分支逻辑提取为方法调用
    • 如果一个 @Builder 方法需要访问的嵌套数据很深,先提取为方法

    9.4 五款 App 的 Builder 模式对比

    App错误总数首次修复说明
    白噪音 16 2 轮 首次接触 ArkUI,API 不熟悉
    时间胶囊 17 2 轮 Builder 约束 + 展开运算符
    冰箱剩菜 22 3 轮 闭包参数模式引入大量错误
    尴尬粉碎机 1 1 轮 模式成熟,仅颜色接口错误
    防骗训练 12 2 轮 主要错误来自大段的 @Builder 重构

    趋势:整体呈下降趋势。尴尬粉碎机达到最低点(1 个错误),防骗训练有所回升(12 个错误)主要是因为情景弹窗代码量大、内部逻辑复杂。


    10. 五款 App 系列总结

    10.1 核心技术覆盖

    五款 App 覆盖了 HarmonyOS Next 应用开发的多个核心技术领域:

    技术领域覆盖 App关键技术点
    多媒体播放 白噪音 @kit.MediaKit、AudioPlayer、混音
    动画系统 白噪音、尴尬粉碎机 animation 属性、动态光晕
    数据持久化 时间胶囊、冰箱剩菜、尴尬粉碎机、防骗训练 Preferences、JSON 序列化
    声明式 UI 全部 @State、@Builder、条件渲染
    Tab 架构 冰箱剩菜、尴尬粉碎机、防骗训练 底部导航、条件切换
    列表交互 时间胶囊、冰箱剩菜、尴尬粉碎机 List + ForEach + swipeAction
    弹窗系统 全部 蒙层 + 浮层、条件渲染
    适老化设计 防骗训练 大字体、高对比度、大按钮

    10.2 数据模型演变

    白噪音 :SoundItem[](6 个预设)
    时间胶囊 :TimeCapsule[](用户生成)
    冰箱剩菜大作战 :FoodItem[] + BattleStats(用户生成 + 统计)
    尴尬粉碎机 :静态 TopicCard[]/ComebackItem[] + EmbarrassmentEntry[]
    防骗训练 :静态 ScamScenario[]/KnowledgeItem[] + TrainProgress

    演变趋势:从纯预设 → 纯用户 → 混合 → 静态为主 + 轻量进度。

    10.3 架构复杂度趋势

    白噪音(单页)→ 时间胶囊(单页+弹窗)→ 冰箱剩菜(3 Tab)→ 尴尬粉碎机(3 Tab)→ 防骗训练(3 Tab)
    767行 955行 1320行 953行 1038行

    冰箱剩菜达到行数峰值(1320 行),后续 App 有意控制复杂度,保持在 1000 行左右。

    10.4 编译错误趋势

    白噪音 16个 → 时间胶囊 17个 → 冰箱剩菜 22个 → 尴尬粉碎机 1个 → 防骗训练 12个
    ↑ ↑ ↑ ↑ ↑
    新手期 探索期 试错期 成熟期 收敛期

    五款 App 的编译错误数呈现"先升后降"的趋势,反映了 ArkUI 的学习曲线:

    • 新手期(1-2款):学习基础语法和 API
    • 探索期(2-3款):尝试复杂模式,踩更多坑
    • 试错期(3款):闭包参数模式带来大量错误
    • 成熟期(4款):模式固定,错误极少
    • 收敛期(5款):大代码量场景下的模式验证

    10.5 核心模式总结

    经过五款 App 的实践,以下模式被反复验证有效:

    模式 1:Stack 三层结构

    Stack() {
    buildBackground() // 背景(可选)
    Column() { /* UI */ } // 内容
    if (dialog) { } // 弹窗
    }

    模式 2:@Builder + 方法提取

    @Builder
    buildXxx() {
    // 只写 UI 组件,不写 let/return
    Text(this.getData())
    }

    getData(): string {
    // 普通方法写逻辑
    return 'xxx';
    }

    模式 3:数组更新

    // 插入
    this.list = [newItem].concat(this.list);
    // 触发渲染
    this.list = this.list.concat([]);
    // 删除
    this.list = this.list.filter(predicate);

    模式 4:数据持久化三件套

    aboutToAppear()loadData()
    每次操作后 → saveData()
    aboutToDisappear()saveData()

    模式 5:Tab 切换

    @State activeTab = 0;
    buildTabContent() {
    if (activeTab === 0) buildTab0()
    else if (activeTab === 1) buildTab1()
    else buildTab2()
    }

    10.6 五篇博客总览

    篇目App核心技术点大约字数
    第 1 篇 沉浸式白噪音 多媒体 + 动画 + Grid 11,000
    第 2 篇 时间胶囊 Preferences + Builder 约束 11,000
    第 3 篇 冰箱剩菜大作战 Tab 架构 + 游戏化 + Grid 弹窗 10,800
    第 4 篇 尴尬粉碎机 静态数据 + 仪式感交互 + 系列对比 9,600
    第 5 篇 老年人防骗训练 适老化设计 + 情景训练 + 系列总结 10,000+

    11. 给 HarmonyOS 新手的建议

    11.1 学习路径推荐

    基于五款 App 的开发经验,推荐以下学习路径:

    第一阶段:理解基础(1-2 周)

    • 学习 ArkTS 语法(接口、类型、泛型)
    • 理解 @State 和 @Builder 的基础用法
    • 做一个简单的单页 App(如待办事项列表)

    第二阶段:掌握核心(2-4 周)

    • 实现弹窗系统(蒙层 + 浮层)
    • 学习 List + ForEach + swipeAction
    • 掌握数据持久化(Preferences)

    第三阶段:复杂场景(4-8 周)

    • 实现 Tab 架构
    • 理解 Builder 的语法约束
    • 建立自己的模式清单

    11.2 常见陷阱

    陷阱表现避免方法
    Builder 中用 let 编译错误 10905209 所有数据获取用方法
    数组不触发渲染 修改了元素 UI 不更新 .concat([]) 创建新引用
    展开运算符 编译错误 arkts-no-spread 使用 .concat()
    对象字面量无类型 编译错误 10605038 先定义 interface
    闭包传参给 @Builder 编译错误 10905204 直接内联 UI

    11.3 五款 App 的实用代码片段

    以下是从五款 App 中提炼的最实用的代码片段:

    片段 1:弹窗模板

    @Builder
    buildDialog() {
    if (this.condition) { // 使用 if 包裹,不用 return
    Column() {
    // 蒙层
    Column()
    .width('100%').height('100%')
    .backgroundColor('rgba(0,0,0,0.5)')
    .onClick(() => { this.condition = false; })
    // 内容
    Column() { /* … */ }
    .width('90%').backgroundColor(Color.White)
    .borderRadius(24).position({ x: '5%', y: '20%' })
    }
    .width('100%').height('100%').position({ x: 0, y: 0 })
    }
    }

    片段 2:数组更新

    // 头部插入
    this.list = [newItem].concat(this.list);
    // 触发渲染(修改元素后)
    item.property = newValue;
    this.list = this.list.concat([]);
    // 过滤删除
    this.list = this.list.filter(predicate);
    // 复制对象
    this.data = this.copyData(this.data);

    片段 3:数据持久化

    async loadData() {
    let ctx = getContext(this);
    let prefs = await preferences.getPreferences(ctx, 'my_db');
    let val = await prefs.get('my_key', '');
    if (val !== '') this.stateData = JSON.parse(val as string);
    }

    async saveData() {
    if (this.prefs) {
    await this.prefs.put('my_key', JSON.stringify(this.stateData));
    await this.prefs.flush();
    }
    }

    片段 4:Tab 架构

    @State activeTab: number = 0;
    buildTabContent() {
    if (this.activeTab === 0) { this.buildTab0() }
    else if (this.activeTab === 1) { this.buildTab1() }
    else { this.buildTab2() }
    }
    buildTabBar() {
    Row() {
    this.buildTabItem(0, '图标1', '标签1')
    this.buildTabItem(1, '图标2', '标签2')
    this.buildTabItem(2, '图标3', '标签3')
    }
    .width('100%').height(56)
    .position({ x: 0, y: '100%' }).translate({ y: 56 })
    }

    11.4 五条心法

  • 数据驱动 UI:所有 UI 变化都来自于 @State 变量的变化
  • Builder 只放 UI:@Builder 方法只写组件声明,逻辑提取到普通方法
  • 先接口后实现:先定义好数据类型和接口,再写 UI 代码
  • 持久化早规划:在设计数据模型时就考虑存储方案
  • 模式复用:每次新 App 都优先使用已验证的模式,不重复造轮子

  • 附录 A:适老化设计速查表

    设计元素常规 App适老化差异
    正文字号 14-16sp 18-20sp +4sp
    标题字号 18-20sp 22-24sp +4sp
    按钮高度 44px 56px+ +12px
    行距 1.2-1.4x 1.5-1.7x +0.3x
    卡片圆角 12px 14-20px 更柔和
    对比度 4.5:1 7:1+ 更高
    信息密度 中高 更多留白
    操作层级 2-3 层 1-2 层 更扁平

    附录 B:五款 App 数据全览

    指标白噪音时间胶囊冰箱剩菜尴尬粉碎机防骗训练
    @State 8 8 14 10 11
    @Builder 8 12 17 15 14
    业务方法 8 12 19 9 12
    总行数 767 955 1320 953 1038
    编译错误 16 17 22 1 12
    修复轮次 2 2 3 1 2
    静态数据 6 声音 6 图标 8 分类+13 单位 20 话题+12 金句 12 情景+6 知识
    持久化
    Tab 数 1 1 3 3 3

    附录 C:完整接口清单

    interface ScamScenario {
    id: number;
    title: string;
    description: string;
    isScam: boolean;
    explanation: string;
    category: string;
    }

    interface KnowledgeItem {
    id: number;
    title: string;
    content: string;
    icon: string;
    color: string;
    }

    interface TrainProgress {
    completedIds: number[];
    correctCount: number;
    totalCount: number;
    highScore: number;
    }

    interface ColorScheme {
    primary: string;
    primaryDark: string;
    accent: string;
    success: string;
    danger: string;
    bg1: string;
    bg2: string;
    cardBg: string;
    text: string;
    textLight: string;
    textHint: string;
    border: string;
    safe: string;
    scam: string;
    }


    本文是"鸿蒙 Next 应用开发实战"系列的第五篇(完结篇)。由 AtomCode 基于 HarmonyOS Next API 24 编写,记录了老年人防骗训练 App 的完整开发过程,以及对五款 App 的系统性技术总结。

    (全文完,约 12000 字)

    赞(0)
    未经允许不得转载:171主机测评 » 鸿蒙 Next 老年人防骗训练 App 开发实战:适老化设计 + 情景训练 + 系列总结
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址