大家好,我是Feri,13年+开发经验,带过团队创过业,深耕嵌入式、鸿蒙、AI和Java,一直盯着程序员成长这件事!
在鸿蒙开发学习中,计算器绝对是“入门黄金项目”——看似简单,却能一次性吃透声明式UI、状态管理、事件处理三大核心,比啃枯燥的文档高效10倍。
今天就以HarmonyOS6.0(API 20)为平台,手把手做一个支持加减乘除、取余、累计运算的智能计算器,2小时搞定,君志所向,一往无前!
一、为什么说计算器是鸿蒙入门的“最优解”?
作为带过无数新人的老程序员,我敢说:选对练手项目,比死记语法重要10倍!而计算器就是鸿蒙入门的“天选项目”: ✅ 覆盖核心技术:声明式UI布局、@State状态管理、事件处理、逻辑封装,全是鸿蒙开发的“高频考点”; ✅ 需求清晰易落地:基础运算+累计运算,不用纠结复杂业务,专注技术本身; ✅ 成就感拉满:写完就能用,比单纯敲demo更有动力,还能举一反三(比如后续加科学计算、主题切换)。
二、5分钟搞定开发环境(新手零踩坑)
先把基础环境搭好,一步到位不绕路:
- 安装DevEco Studio(鸿蒙官方最新版,适配NEXT);
- 创建HarmonyOS应用工程:API Version 20(重点!适配NEXT版本),开发语言选ArkTS;
- 验证环境:启动设备模拟器,确保空项目能正常运行(避免后续代码写好却跑不起来)。
三、核心需求拆解:把计算器拆成“看得见+算得对”
先理清要实现的功能,再对应到UI和逻辑,新手也能思路清晰:
👀 视觉层(看得见)
- 显示屏:分两行,上一行显示计算表达式(如“1+2=”),下一行超大字体显示结果;
- 按钮组:5行布局,包含清除(AC)、小数点、取余(%)、四则运算、数字0-9、等号,按钮样式统一且易点击。
🧮 逻辑层(算得对)
- 数字/小数点输入:支持拼接多位数、小数;
- 运算逻辑:加减乘除+取余,支持累计运算(比如1+2=3,再+5直接算3+5);
- 重置功能:AC一键清空所有状态,重新开始。
四、保姆级编码:逐模块解析,每行代码都讲透
直接上完整代码+关键注释,分“状态定义→UI布局→核心函数”三部分,不怕你看不懂!
第一步:定义响应式状态(数据驱动UI的核心)
用@State修饰的变量,能让UI跟着数据自动更新,这是鸿蒙声明式UI的精髓:
typescript
体验AI代码助手
代码解读
复制代码
@Entry
@Component
struct Demo2Page {
// 计算表达式(如"1+2="),@State驱动UI实时更新
@State str:string="";
// 计算结果,超大字体展示
@State result:number=0;
// 第一个操作数(字符串存储,方便拼接小数)
num1:string="";
// 第二个操作数(同理,支持小数)
num2:string="";
// 操作符:+、-、*、/、%
op:string="";
// 下面是build布局和核心函数...
}
💡 技巧:num1/num2用字符串存储,避免小数拼接时出现数字类型的坑(比如0.1+0.2≠0.3的问题先不纠结,聚焦核心逻辑)。
第二步:搭建UI布局(声明式UI的简洁之美)
用Column+Row嵌套实现布局,结构清晰,新手复刻无压力:
typescript
体验AI代码助手
代码解读
复制代码
build() {
Column(){
// 1. 显示屏区域:表达式+结果,右对齐更符合计算器习惯
Column({space:5}){
// 计算表达式:小字体,最多3行
Text(this.str)
.textAlign(TextAlign.End) // 右对齐,贴合计算器使用习惯
.padding({right:5})
.maxLines(3)
.width("100%")
// 计算结果:超大字体+加粗,醒目易读
Text(this.result+"")
.fontSize(50)
.fontWeight(700)
.textAlign(TextAlign.End)
.padding({right:5})
.width("100%")
}
.width("100%")
.margin({top:10,bottom:5})
// 2. 按钮组:5行布局,间距均匀,样式统一
Column({space:10}){
// 第一行:AC(清除)、小数点、%(取余)、÷(除法)
Row({space:30}){
Button("AC")
.fontSize(20)
.fontWeight(600)
.backgroundColor(Color.Grey)
.width("20%")
.onClick(()=>{
this.getOp("AC"); // 点击触发清除逻辑
})
Button(".")
.fontSize(30)
.fontWeight(900)
.backgroundColor(Color.Grey)
.width("20%")
.onClick(()=>{
this.getNum("."); // 点击输入小数点
})
Button("%")
.fontSize(20)
.fontWeight(600)
.backgroundColor(Color.Grey)
.width("20%")
.onClick(()=>{
this.getOp("%"); // 点击选择取余运算
})
Button("/")
.fontSize(30)
.fontWeight(600)
.backgroundColor(Color.Grey)
.width("20%")
.onClick(()=>{
this.getOp("/"); // 点击选择除法运算
})
}
.width("100%")
.justifyContent(FlexAlign.SpaceAround) // 按钮均匀分布
.margin({top:5})
// 第二行:7、8、9、×(乘法)
Row({space:30}){
Button("7").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("7");})
Button("8").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(900).onClick(()=>{this.getNum("8");})
Button("9").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("9");})
Button("X").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getOp("*");})
}
.width("100%").justifyContent(FlexAlign.SpaceAround).margin({top:5})
// 第三行:4、5、6、-(减法)
Row({space:30}){
Button("4").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("4");})
Button("5").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(900).onClick(()=>{this.getNum("5");})
Button("6").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("6");})
Button("-").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getOp("-");})
}
.width("100%").justifyContent(FlexAlign.SpaceAround).margin({top:5})
// 第四行:1、2、3、+(加法)
Row({space:30}){
Button("1").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("1");})
Button("2").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(900).onClick(()=>{this.getNum("2");})
Button("3").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("3");})
Button("+").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getOp("+");})
}
.width("100%").justifyContent(FlexAlign.SpaceAround).margin({top:5})
// 第五行:占位按钮、0、=(等号,加宽更易点击)
Row({space:30}){
Button() {
SymbolGlyph($r("sys.symbol.list_number"))
.fontColor([Color.White])
.fontWeight(800)
.fontSize(20)
.padding({top:10,bottom:10})
}.backgroundColor(Color.Grey).width("20%")
Button("0").width("20%").backgroundColor(Color.Grey).fontSize(20).fontWeight(600).onClick(()=>{this.getNum("0");})
Button("=")
.fontSize(20)
.fontWeight(900)
.backgroundColor(Color.Grey)
.width("50%") // 等号加宽,符合用户操作习惯
.onClick(()=>{
this.getOp("="); // 触发计算逻辑
})
}
.width("100%").justifyContent(FlexAlign.SpaceAround).margin({top:5})
}
}
.height('100%')
.width('100%')
}
💡 布局技巧:用FlexAlign.SpaceAround让按钮自动均匀分布,不用手动算间距;等号加宽到50%,解决小按钮点击不准的问题。
第三步:封装核心函数(逻辑解耦,代码更易维护)
把数字输入、操作符处理、计算逻辑拆成3个函数,新手也能学会“模块化编程”:
typescript
体验AI代码助手
代码解读
复制代码
// 1. 处理数字/小数点输入:拼接操作数
getNum(n:string){
// 操作符为空→输入第一个操作数;否则输入第二个操作数
if(this.op===""){
this.num1+=n;
}else {
this.num2+=n;
}
this.str+=n; // 实时更新表达式显示
}
// 2. 处理操作符(AC、=、+-*/%)
getOp(o:string){
if(o==="="){
this.getResult(); // 等号触发计算逻辑
}else if(o==="AC"){
// 清空所有状态,重置计算器
this.str="";
this.result=0;
this.op="";
this.num1="";
this.num2="";
}else {
// 支持连续运算:若已有操作符,先计算上一轮结果
if(this.op!==""){
this.getResult();
}
this.op=o; // 记录当前操作符
this.str+=o; // 更新表达式显示
}
}
// 3. 核心计算逻辑:根据操作符计算结果
getResult(){
// 字符串转数字,执行对应运算
let n1:number=Number(this.num1);
let n2:number=Number(this.num2);
switch (this.op){
case "+":this.result=n1+n2;break;
case "-":this.result=n1-n2;break;
case "*":this.result=n1*n2;break;
case "/":this.result=n1/n2;break;
case "%":this.result=n1%n2;break;
}
this.str+="="+this.result; // 表达式追加结果(如"1+2=3")
// 累计运算关键:把结果作为下一轮的第一个操作数
this.num1=this.result+"";
this.op="="; // 标记已计算,避免重复操作
this.num2=""; // 清空第二个操作数
}
💡 核心亮点:支持累计运算!比如计算1+2=3后,直接点+5,会自动用3+5计算,和手机自带计算器的逻辑完全一致。
五、效果展示:写完就能用,丝滑度拉满
👉 操作流程:输入数字→选运算符号→输入第二个数字→点等号,结果秒出;AC一键清空,连续运算也丝滑,完全能当日常计算器用!
六、深挖关键技术:吃透原理,不止会写计算器
作为12年老程序员,必须提醒你:写代码只是第一步,理解背后的原理才是进阶的关键!
🚀 声明式UI的核心优势(为什么鸿蒙写UI这么快?)
- 数据驱动更新:只要@State变量变了,UI自动更新,不用手动操作DOM(对比前端原生开发,少写80%的更新代码);
- 状态自动绑定:@State修饰的变量和UI组件自动绑定,无需手动添加监听事件;
- 高性能渲染:鸿蒙底层优化了渲染管线,状态变更只刷新关联组件,不重绘整个页面,性能更优。
🧠 @State状态管理的底层逻辑
- 响应式原理:@State本质是给变量添加“监听钩子”,变量修改时会触发UI刷新信号;
- 更新流程:变量变更 → 框架检测到状态变化 → 重新渲染关联的UI组件 → 页面更新;
- 多状态协同:str(表达式)和result(结果)两个@State变量,各自驱动对应Text组件,互不干扰却能协同展示完整计算过程。
七、进阶彩蛋(可选):给计算器加“buff”
学会基础版后,试试这些优化,让计算器更实用(也是面试加分项):
- 🎨 样式美化:给按钮加圆角、点击高亮效果,区分数字键(灰色)和运算键(橙色);
- ⚠️ 异常处理:添加“除数不能为0”“小数点只能输一次”的判断,避免程序崩溃;
- 🧮 功能扩展:增加平方、开根号、正负号切换,升级成简易科学计算器。
最后说两句
这个计算器项目看似简单,却藏着鸿蒙开发的核心思维——“数据驱动UI”。
如果大家想考取鸿蒙开发者认证的,欢迎加入我的专属考试链接中:developer.huawei.com/consumer/cn…
作为资深程序员,我始终认为:入门新技术最好的方式,就是做一个能跑起来、能用起来的小项目。
后续还会分享更多鸿蒙NEXT实战小项目(记事本、待办清单),帮你从入门到进阶,成长路上有我相伴,君志所向,一往无前!