HarmonyOS应用实例:用ArkTS实现100以内加法竖式计算达人

发布时间:2026/10/13 12:50:33
HarmonyOS应用实例:用ArkTS实现100以内加法竖式计算达人 这次想聊的是 HarmonyOS 应用实例 22100以内加法『竖式计算达人』。这个名字看着像个给孩子玩的小工具但拆开以后你会发现它把随机出题、竖式排版、进位逻辑、答案校验、分步讲解全塞进了一个单页面应用里非常典型的“小而全”练手项目。作为 HarmonyOS 应用开发实例它的价值不只是“会做一道加法题”而是能让你把 ArkTS 的声明式 UI、状态管理、事件响应和纯业务函数串起来跑一遍。如果你正在学 HarmonyOS 应用开发又不想一上来就碰复杂的网络请求和数据库这类计算类小工具是最好的起点。它不需要后端、不需要复杂权限界面逻辑直观坑也集中在前端排版和状态刷新上。哪怕你完全没有做过鸿蒙应用跟着这个思路走下来也能搞出一个能正常出题、判题、讲步骤的完整应用。这篇就把我的设计过程、核心代码和踩坑点完整写出来。1. 需求拆解与整体设计思路1.1 先想清楚这个应用到底要做什么很多人在拿到“100以内加法”这个需求时第一反应是“不就是随机两个数然后判断结果吗”。如果真是这么做做出来的东西和一张口算纸没什么区别。竖式计算达人的核心差异在于“竖式”两个字。孩子平时在作业本上写竖式讲究的是数位对齐、进位标记、从个位算起这些细节才是练习的价值。所以我定的功能清单是这样的随机生成一道 100 以内加法题两个加数可以是两位数和不超过 100。题目以竖式形式展示十位、个位严格对齐有进位时显示进位标记。孩子在下方的输入框填写计算结果点击按钮检查。答对计分答错允许重试但同一题只能计一次分。支持查看分步计算过程明确展示“个位先加、满十进一、十位再加”的步骤。提供下一题按钮连续出题形成练习闭环。从这组需求能看出应用的重点其实不在加法本身而在怎么把“竖式计算的思路”转译成 UI 和逻辑。加法谁都会但要让一个刚接触竖式的孩子看得懂、练得下去就需要在排版和反馈上下足功夫。1.2 技术选型为什么用 ArkTS ArkUIHarmonyOS 应用开发现在的主流方案是 Stage 模型搭配 ArkTS 语言和 ArkUI 声明式框架。针对这个项目不需要引入任何第三方库单页面就能搞定。选 ArkTS 而不是旧式 Java XML 或类 Web 开发主要有几个原因声明式 UI 和状态绑定非常契合这种交互场景。界面上的题目、得分、反馈信息都是状态状态一变 UI 自动刷新比手动操作 DOM 或 findView 舒服太多。内置组件足够用。Column、Row、Text、TextInput、Button、Divider 这几个组件就能拼出整个竖式界面。业务逻辑集中在随机数生成和字符串拼接上ArkTS 的类型约束反而能帮你提前发现数据结构设计问题。如果动用 Canvas 自绘竖式当然也能做而且排版更自由但开发量会明显变大。这个项目的定位是计算练习工具不是绘画渲染 Demo所以用基础组件拼版是最务实的方案。后续想追求更精美的竖式展示再把某一块替换成 Canvas 不迟。1.3 页面结构与状态设计整个应用只有一个页面但页面内部有清晰的区块划分。从上到下依次是顶部信息栏显示当前是第几题、当前得分。竖式题目卡片这是核心展示区包含进位标记、两个加数、横线、答案输入位。操作区检查答案、查看过程、下一题这三个按钮。反馈区显示对错提示、分步计算步骤、鼓励文案。状态变量也不是随手一放而是和用户操作一一对应。我用的核心状态如下状态变量作用变化时机question当前题目的完整数据生成新题时整体替换inputValue用户输入的答案字符串输入框每次变化feedback对错提示文案点击检查时hasAnswered当前题是否已计分首次检查后置为 true下一题重置showProcess是否展示分步过程点击查看过程或答错后score / total得分和总题数每次判题后更新这里要注意一个常见的坑State 修饰的变量如果你只修改对象内部的某个字段在某些情况下 UI 不一定刷新。最稳妥的做法是每次出题时直接生成一个全新对象整体赋值给 question而不是在旧对象上改字段。这种“整体替换”的思路在后面写代码时会反复出现。2. 出题算法与竖式数据结构2.1 数据结构用对象描述一道竖式题竖式题不能只存两个加数和结果因为界面展示和分步讲解都需要按位拆分。我定义了一个接口interface Question { addend1: number; // 第一个加数 addend2: number; // 第二个加数 sum: number; // 两数和 tens1: number; // 第一个加数十位 ones1: number; // 第一个加数个位 tens2: number; // 第二个加数十位 ones2: number; // 第二个加数个位 carry: number; // 个位相加是否进位0 或 1 resultOnes: number; // 个位结果 resultTens: number; // 十位结果 resultHundreds: number; // 百位结果0 或 1 }为什么要把“原数字”和“各数位”都存下来因为不同场景需要不同视角。输入框校验用 addend1 addend2竖式排版用 tens1、ones1、tens2、ones2分步讲解用 carry、resultOnes、resultTens。如果只有两个加数的整体数字每次展示前都要再做一次除法和取余逻辑散落各处很容易出 bug。把所有派生数据在生成题目时就算好后续所有模块只读取不重复计算整个代码会清爽很多。这里也体现了数据建模的重要性界面长什么样、讲解流程怎么走会反过来决定数据结构怎么设计。2.2 随机出题按“数位”生成而不是按“和”生成很多人的第一版出题函数是“直接随机两个数判断和是否小于等于100”。这样做也能用但会出现两个问题一是算出来的题可能是个位和十位都完全不需要进位的简单题竖式练习价值低二是很难在出题阶段控制难度。我更推荐按位生成function generateQuestion(): Question { for (let i 0; i 100; i) { const tens1 Math.floor(Math.random() * 10); const tens2 Math.floor(Math.random() * 10); const ones1 Math.floor(Math.random() * 10); const ones2 Math.floor(Math.random() * 10); const addend1 tens1 * 10 ones1; const addend2 tens2 * 10 ones2; const sum addend1 addend2; // 和不能超过 100 if (sum 100) continue; // 排除 00 这种没有练习意义的题 if (addend1 0 addend2 0) continue; // 至少一个加数是两位数否则竖式只有一行和“横式”没区别 if (tens1 0 tens2 0) continue; const onesSum ones1 ones2; const carry onesSum 10 ? 1 : 0; const resultOnes onesSum % 10; const tensSum tens1 tens2 carry; const resultHundreds tensSum 10 ? 1 : 0; const resultTens tensSum % 10; return { addend1, addend2, sum, tens1, ones1, tens2, ones2, carry, resultOnes, resultTens, resultHundreds }; } // 极端情况兜底几乎不会走到 return createDefaultQuestion(); }按位生成的另一个好处是后续想加难度分级非常容易。比如想出一道人教版小学一年级常见的“个位相加进一位”的题可以先生成 ones1 和 ones2让它们满足 ones1 ones2 10再生成十位。想出一道路程更长的连续进位题就让十位相加再加进位后也变成 10 或更多。先用随机 重试把基础版本跑起来后续优化难度时再改成“先定进位规则再生成数位”的定向逻辑。2.3 防止题目重复与难度失衡纯随机出题有一个副作用连续几题可能是完全一样的。孩子练着练着就会发现“这题刚才做过”练习效果打折扣。我处理的办法很简单维护一个最近题目缓冲const history: string[] []; function isDuplicate(q: Question): boolean { const key ${q.addend1}${q.addend2}; return history.includes(key); } function recordHistory(q: Question): void { const key ${q.addend1}${q.addend2}; history.push(key); if (history.length 5) { history.shift(); } }生成题目后先查 history重复就重新生成新题生成后把 key 放入 history。这样能避免连续 5 题内出现重复又不会因为历史记录无限增长导致内存问题。难度失衡方面完全随机容易产生大量 3020、4010 这类“十位相加不进位、个位相加也不进位”的简单题目孩子熟练以后会觉得无聊。常见做法是引入难度参数比如小学低年级可以分成三个等级入门两个加数都是一位数或整十数练习数位对齐。进阶个位相加需要进位但十位相加不进位。挑战个位、十位都有可能进位甚至出现 991100 这样的边界题。基础版可以先不做等级选择但出题时要避免两个加数全是 0 开头保证竖式至少有两行数字。实测下来加了这个过滤后题目整体观感会好很多。3. 界面布局与竖式展示实现3.1 竖式排版的核心思路固定列宽竖式在纸上是靠数位上下对齐但在手机上直接写一串文本很难做到对齐。我的做法是固定三列百位列、十位列、个位列每个数字占一个固定宽度容器空格也用同样宽度的 Text 填充。ArkUI 里没有像 HTML 那样简单的 table 布局但用 Row 加固定宽度 Text 完全可以模拟。下面这个自定义构建方法是我实际在用的Builder numberRow(value: number, showPlus: boolean) { Row() { Text(showPlus ? : ) .width(40) .fontSize(32) .textAlign(TextAlign.Center); Text(value 100 ? String(Math.floor(value / 100)) : ) .width(40) .fontSize(32) .textAlign(TextAlign.Center); Text(value 10 ? String(Math.floor(value / 10) % 10) : ) .width(40) .fontSize(32) .textAlign(TextAlign.Center); Text(String(value % 10)) .width(40) .fontSize(32) .textAlign(TextAlign.Center); } }你需要理解这里的关键不是把“35”当成一个整体 Text 放进去而是拆成“3”和“5”两个独立 Text分别塞在十位和个位列。这样无论上面的数是 35、7 还是 100个位永远在同一列。如果不拆开一旦遇到不同位数的数下方数字就会对不齐这是竖式应用最容易出现的问题。进位标记行也一样固定三列Builder carryRow() { Row() { Text( ) .width(40) .fontSize(24) .textAlign(TextAlign.Center); Text( ) .width(40) .fontSize(24) .textAlign(TextAlign.Center); Text(this.question.carry 1 ? 1 : ) .width(40) .fontSize(24) .fontColor(#E84026) .textAlign(TextAlign.Center); } }因为题目和不超过 100百位最多也只可能是 1所以三列足够。整个竖式区域用 Column 纵向排列进位行、第一个加数、第二个加数、横线、答案输入区。3.2 横线与答案输入区竖式下方需要一个横线ArkUI 里可以用 Divider也可以用一个高度很小的 Column 自己画。我习惯用 DividerDivider() .strokeWidth(2) .color(#666666) .width(180)答案区我没有直接显示结果而是放了一个 TextInput让用户把计算结果填进去TextInput({ placeholder: 输入答案, text: this.inputValue }) .type(InputType.Number) .maxLength(3) .width(160) .fontSize(28) .textAlign(TextAlign.Center) .onChange((value: string) { this.inputValue value; })设置.type(InputType.Number)后手机会弹出数字键盘对孩子更友好。不过要注意数字键盘并不代表输入内容一定是纯数字所以校验逻辑里仍然要做兜底判断。3.3 小屏适配与可读性细节竖式练习的主要用户是孩子所以字体和按钮都不能太小。我实测下来数字字号 32fp、按钮高度 44vp 以上比较合适。数字列宽设成 40vp整个竖式卡片宽度控制在 200vp 左右在大多数手机竖屏下都能完整显示。还有一个容易忽略的点进位标记的颜色可以用醒目的红色但不要太刺眼。我用的是 #E84026和主文本的 #182431 区分开既醒目又不花哨。反馈文案也要语气鼓励式答对显示“太棒了”答错显示“再想想”不要把“错误”“不对”这种生硬的字眼放太大。如果需要适配平板可以给整个竖式卡片加一个最大宽度约束然后用.constraintSize({ maxWidth: 360 })限制内容宽度避免在宽屏上被拉得很散。考虑到这个应用主打手机场景基础版本不用做得太复杂。4. 核心交互与校验逻辑实现4.1 输入校验不能只相信数字键盘用户输入答案后点击“检查答案”按钮触发校验函数。这里的校验分两层第一层输入是否为空、是否纯数字。第二层输入的数字是否等于题目结果。第一层校验一定要做因为即使设置了数字键盘有些输入法还是能输入空格、小数点甚至全角字符。处理方式checkAnswer() { const input this.inputValue.trim(); if (input || !/^\d$/.test(input)) { this.feedback 请输入数字; return; } const answer parseInt(input, 10); if (answer this.question.sum) { if (!this.hasAnswered) { this.hasAnswered true; this.score 10; } this.feedback 太棒了回答正确; this.showProcess true; } else { this.feedback 再想想看看下面的计算过程; this.showProcess true; } this.total 1; }这里的hasAnswered很关键。如果不加这个标记孩子答对后觉得好玩反复点“检查答案”分数会不断累加。加了以后同一题只计一次分总分才是真实的练习成绩。答对后自动展示分步过程也是一个不错的体验细节。孩子即使做对了也能再看一遍竖式计算的算法路径强化记忆。4.2 分步计算过程的动态展示分步讲解是“竖式计算达人”区别于普通口算应用的核心功能。我实现的方式不是做动画而是按步骤生成文本再用列表渲染出来。这样做开发量小阅读效果也足够清晰。生成步骤的函数function buildProcessText(q: Question): string[] { const steps: string[] []; const onesSum q.ones1 q.ones2; const step1 第1步个位 ${q.ones1} ${q.ones2} ${onesSum}; steps.push(q.carry 1 ? ${step1}写${q.resultOnes}向十位进 1 : ${step1}写${q.resultOnes}); const tensSum q.tens1 q.tens2 q.carry; if (q.resultHundreds 1) { steps.push(第2步十位 ${q.tens1} ${q.tens2} ${q.carry} ${tensSum}写0向百位进 1); steps.push(所以结果是${q.sum}); } else { steps.push(第2步十位 ${q.tens1} ${q.tens2} ${q.carry} ${q.resultTens}写${q.resultTens}); steps.push(所以结果是${q.sum}); } return steps; }展示时用条件渲染加循环if (this.showProcess) { Column({ space: 6 }) { ForEach(buildProcessText(this.question), (step: string) { Text(step) .fontSize(18) .width(100%) .margin({ top: 4 }) .lineHeight(28) }) } .padding(12) .backgroundColor(#F5F7FA) .borderRadius(12) .width(100%) }这里有个小设计进位时十位的结果展示为“写0向百位进 1”这样 100 这种边界情况也能讲清楚。孩子看到竖式上的进位 1 对应到讲解文本里的“进 1”理解起来非常直接。4.3 下一题与状态重置“下一题”按钮触发nextQuestion() { let next: Question; let guard 0; do { next generateQuestion(); guard; } while (isDuplicate(next) guard 20); recordHistory(next); this.question next; this.inputValue ; this.feedback ; this.showProcess false; this.hasAnswered false; }这里有一个细节把“生成新题”和“重置状态”分开写逻辑才清楚。最容易犯的错是只改题目不清空输入框导致上一题的答案留在空里孩子看到以为下一题已经填好了。在写代码时我把所有需要重置的变量列在同一个函数里逐个检查一遍基本就不会漏。另外为什么用 do...while 而不是直接生成因为 isDuplicate 有概率连续返回 true加一个最大重试次数 20 作为兜底防止极端情况下死循环。虽然实际运行中这个概率非常低但防御性编程还是必要的。4.4 按钮状态与用户引导界面上三个按钮可以进一步区分状态。检查答案按钮在hasAnswered为 true 时禁用避免重复点击查看过程按钮和检查答案功能有重叠但保留它可以让做对的孩子也能主动看讲解下一题按钮始终可用。ArkUI 里禁用按钮可以直接控制.enabled()Button(检查答案) .enabled(!this.hasAnswered) .onClick(() this.checkAnswer())按钮禁用后颜色会变灰正好给孩子一个“这题已经答过了”的视觉信号。这个小细节不需要额外代码状态但使用体验会提升不少。5. 常见问题、优化思路与实测心得5.1 竖式对齐问题不是玄学是固定宽度没做对我用这个应用给身边人测试时反馈最多的就是“怎么有时候数字会对不齐”。排查后发现基本都是同一个原因有人在实现时把整个数字当成 Text然后用空格去凑位置。不同字体下空格的宽度和数字宽度不同换一台设备就歪了。解决办法很明确别依赖空格把所有数位拆开每个数位放到固定宽度的容器里。Text 的 width 固定后textAlign 设为居中无论数字是 0 还是 9列的位置都完全一致。这也是为什么 Builder 里每个 Text 都要写.width(40)。如果后续想支持更多位数比如三位数加法只需要扩展列数把每个 Text 的宽度统一改一下即可整体结构不需要推倒重来。5.2 状态不刷新与重复计分有朋友按我这个思路写遇到一个问题输入正确答案后界面上的得分没变。查了半天发现他把 question 和 score 都写在一个自定义对象里然后用State修饰这个对象再修改this.data.score this.data.score 10。在 ArkUI 中State 对嵌套属性变化的观察有限制这种写法并不总能触发 UI 更新。我的建议是把需要响应式更新的字段直接定义成独立的 State 变量比如State score: number 0。对于引用类型整体替换对象不要只修改它的属性。遵循这两条状态刷新问题能减少九成。重复计分问题则靠hasAnswered这个标志位解决上面已经详细说过。5.3 出题质量与边界情况测试这类应用的隐藏风险都藏在边界。我测试时重点跑了以下场景991100百位出现 1竖式要显示三列。5611两个加数都是一位数竖式左侧会出现大量空白。12719第二个加数是一位数十位留白。4555100个位进位且十位也进位分步讲解要正确显示“十位写 0 向百位进 1”。自己手写测试太累可以在开发阶段临时把generateQuestion改成带参数的定向生成函数比如generateQuestionWithCarry(true)专门用来造边界题。我测试时就是这么干的等边界题都通过后再换回完全随机模式。5.4 后续扩展方向与性能优化这个应用目前的性能没有任何压力单页面、几个组件、轻量循环运行非常流畅。后续如果想做成真正能上架给孩子长期使用的产品可以考虑这些方向难度等级选择入门、进阶、挑战对应不同的进位规则。错题本答错的题自动收集后续集中复习。计时挑战一分钟内能答对多少题增加游戏化激励。家长设置限制每日练习时长、查看正确率曲线。语音播报把题目读出来适合学龄前儿童。代码层面优化的空间不大但如果要上版本迭代建议把出题、校验、步骤生成这些纯函数放到单独的工具文件里页面只负责状态和渲染。这样将来加测试用例、做单元测试都会容易很多。我在实际开发中发现一个看起来简单的“加法练习器”真正做出来并且把各种边界情况处理好至少要预留半天时间。竖式排版和随机出题本身不难难的是站在孩子的视角把所有反馈细节补充完整。比如答错之后要看得到过程、答对之后要有正向激励、题目不能太简单也不能超出范围这些都会决定它是不是一个真正“能用”的学习工具。如果你也在做类似的 HarmonyOS 应用实例我建议先把界面骨架搭出来再填逻辑最后专门花一点时间测边界题。别小看这个 100 以内加法的小项目它把声明式 UI 的状态管理和业务模型配合这件事讲得明明白白做完之后你会对 State、Builder、组件事件这些核心概念有更具体的理解。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询