
HarmonyOS ArkTS 实战实现一个标准计算器项目效果本文实现的是一个基于 HarmonyOS 和 ArkTS 的标准计算器。项目中使用 ArkUI 组件完成页面布局通过State管理状态数据实现加减乘除四则运算、小数运算、清除、退格、正负切换和百分比等标准计算器功能。最终运行效果如下页面主要包含以下内容顶部应用标题上方显示区域显示计算表达式大字体显示当前数字下方4×5按钮网格数字键0-9加减乘除运算符等于、清除、退格、小数点、正负、百分比按钮页面整体采用 ArkUI 声明式布局。本文重点是演示如何在 HarmonyOS 项目中使用 ArkTS 和 ArkUI 实现一个计算器单页面应用。项目代码主要写在entry/src/main/ets/pages/Index.ets文件中适合作为 HarmonyOS ArkTS 入门到进阶之间的练习案例。前言计算器是每个手机必备的工具也是学习编程最经典的入门项目。实现一个计算器看起来简单但要处理好各种边界情况并不容易连续运算、小数、除以零、运算符切换等等。从应用开发角度来看这个项目不依赖后端接口也不需要数据库但能练习 ArkTS 中的状态管理、网格布局、按钮交互、表达式计算和边界情况处理等内容。本文基于 HarmonyOS 和 ArkTS 实现一个标准计算器。支持加减乘除四则运算有标准计算器的所有常用功能界面简洁操作流畅。这个项目的核心不是简单的加减乘除而是正确处理各种计算状态和边界情况。每一次按钮点击都会改变计算器的状态这正是 ArkUI 声明式开发的基本思想。一、项目目标本次实践主要实现以下目标创建 HarmonyOS ArkTS 页面使用Entry和Component定义页面组件使用State管理页面状态实现0-9数字输入加减乘除四则运算小数点输入等于计算结果全部清除AC退格删除正负号切换百分比计算连续运算支持使用Builder封装计算器按钮完成一个可以运行的标准计算器页面。这个项目虽然是单页面应用但它实现了完整的计算器功能处理了各种边界情况比普通静态页面更适合练习 ArkTS。二、技术栈类型内容开发方向HarmonyOS 应用开发开发语言ArkTSUI 框架ArkUISDK 版本HarmonyOS API 23 及以上工程模型Stage 模型核心组件Text / Button / Column / Row / Grid状态管理State数据处理四则运算 / 状态机 / 边界处理项目入口entry/src/main/ets/pages/Index.ets运行平台模拟器或真机本项目是 HarmonyOS 原生 ArkTS 项目。页面主体由 ArkUI 组件构建核心逻辑写在Index.ets文件中不依赖后端接口也不需要额外配置数据库。三、为什么选择标准计算器项目标准计算器适合作为 ArkTS 练习项目主要有以下几个原因。第一经典入门项目。几乎所有编程入门都会做计算器是检验基础能力的好项目。第二实用性强。计算器是日常最常用的工具之一。第三适合练习状态管理。计算器有多种状态输入数字、输入运算符、显示结果等。第四适合练习网格布局。计算器按钮是规则的网格练习Grid或Flex布局。第五适合练习边界处理。除以零、多个小数点、连续运算符等情况都需要处理。第六扩展空间比较大。基础功能完成后可以继续增加科学计算、历史记录、单位换算、进制转换和主题切换。在本项目中当前数字、运算符、上一个数字是核心状态。所有计算逻辑都基于这些状态。四、功能规则说明按钮布局AC/-%÷789×456-1230.⌫运算规则输入数字时连续输入组成多位数点击运算符后保存当前数字准备输入下一个再次点击运算符时先计算之前的结果点击等于显示最终结果AC清除所有状态退格删除最后一位/-切换正负号%将当前数字除以100除以0显示Error五、项目结构本项目主要修改首页文件entry └── src └── main └── ets └── pages └── Index.ets其中文件作用Index.ets编写页面结构、状态数据和计算逻辑本文不涉及复杂路由也不需要额外创建多个页面。对于练习项目来说把主要逻辑集中在一个Index.ets文件中更方便理解。六、核心实现思路本项目的核心流程如下使用State保存当前显示数字、上一个数字、当前运算符点击数字按钮追加数字点击运算符保存当前数字和运算符点击等于时根据运算符计算结果处理小数点确保只有一个处理正负切换处理百分比处理退格AC重置所有状态处理除以零等错误情况。项目中最重要的状态变量如下State display: string 0 State previousValue: number 0 State operator: string State shouldResetDisplay: boolean false State expression: string 其中状态变量作用display当前显示的数字previousValue上一个操作数operator当前运算符shouldResetDisplay输入下一个数字时是否重置显示expression表达式显示这些状态构成了计算器的状态机正确处理状态转换是计算器正确运行的关键。七、Index.ets 完整代码打开文件entry/src/main/ets/pages/Index.ets将其中内容替换为下面代码EntryComponentstruct Index{Statedisplay:string0StatepreviousValue:number0Stateoperator:stringStateshouldResetDisplay:booleanfalseStateexpression:stringprivateinputNumber(num:string):void{if(this.shouldResetDisplay){this.displaynumthis.shouldResetDisplayfalse}else{if(this.display0num!.){this.displaynum}elseif(num.this.display.includes(.)){return}else{this.displaynum}}}privateinputOperator(op:string):void{letcurrentValueparseFloat(this.display)if(this.operator!!this.shouldResetDisplay){this.calculate()currentValueparseFloat(this.display)}this.previousValuecurrentValuethis.operatoropthis.shouldResetDisplaytruethis.expression${this.formatNumber(this.previousValue)}${this.getOperatorSymbol(op)}}privatecalculate():void{if(this.operator)returnletcurrentValueparseFloat(this.display)letresult0switch(this.operator){case:resultthis.previousValuecurrentValuebreakcase-:resultthis.previousValue-currentValuebreakcase*:resultthis.previousValue*currentValuebreakcase/:if(currentValue0){this.displayErrorthis.operatorthis.shouldResetDisplaytruethis.expressionreturn}resultthis.previousValue/currentValuebreak}this.expression${this.formatNumber(this.previousValue)}${this.getOperatorSymbol(this.operator)}${this.formatNumber(currentValue)}this.displaythis.formatResult(result)this.operatorthis.shouldResetDisplaytrue}privateclearAll():void{this.display0this.previousValue0this.operatorthis.shouldResetDisplayfalsethis.expression}privatebackspace():void{if(this.shouldResetDisplay||this.displayError)returnif(this.display.length1||(this.display.length2this.display.startsWith(-))){this.display0}else{this.displaythis.display.substring(0,this.display.length-1)}}privatetoggleSign():void{if(this.display0||this.displayError)returnif(this.display.startsWith(-)){this.displaythis.display.substring(1)}else{this.display-this.display}}privatepercent():void{letvalueparseFloat(this.display)this.displaythis.formatResult(value/100)this.shouldResetDisplaytrue}privateformatNumber(num:number):string{if(Number.isInteger(num)){returnnum.toString()}returnnum.toString()}privateformatResult(num:number):string{if(Number.isInteger(num)){returnnum.toString()}returnparseFloat(num.toFixed(10)).toString()}privategetOperatorSymbol(op:string):string{switch(op){case:returncase-:return-case*:return×case/:return÷default:returnop}}BuilderCalcButton(text:string,color:string,bgColor:string,onClick:()void,flex:number1){Button(text).layoutWeight(flex).height(64).fontSize(24).fontWeight(FontWeight.Medium).fontColor(color).backgroundColor(bgColor).borderRadius(32).onClick(onClick)}build(){Column(){Text(计算器).fontSize(28).fontWeight(FontWeight.Bold).fontColor(#182431).margin({top:22})Text(基于 HarmonyOS ArkTS 的标准计算器).fontSize(14).fontColor(#6B7280).margin({top:8,bottom:20})Column(){Blank()if(this.expression){Text(this.expression).fontSize(18).fontColor(#9CA3AF).width(100%).textAlign(TextAlign.End).margin({bottom:8})}Text(this.display).fontSize(56).fontWeight(FontWeight.Light).fontColor(#182431).width(100%).textAlign(TextAlign.End).maxLines(1).textOverflow({overflow:TextOverflow.Ellipsis})}.width(100%).height(180).padding(20).backgroundColor(Color.White).borderRadius(16).margin({bottom:16}).shadow({radius:8,color:#08000000,offsetX:0,offsetY:2})Column(){Row(){this.CalcButton(AC,#FFFFFF,#9CA3AF,(){this.clearAll()})this.CalcButton(/-,#FFFFFF,#A5A5A5,(){this.toggleSign()})this.CalcButton(%,#FFFFFF,#A5A5A5,(){this.percent()})this.CalcButton(÷,#FFFFFF,#FF9F0A,(){this.inputOperator(/)})}.width(100%).margin({bottom:12})Row(){this.CalcButton(7,#FFFFFF,#333333,(){this.inputNumber(7)})this.CalcButton(8,#FFFFFF,#333333,(){this.inputNumber(8)})this.CalcButton(9,#FFFFFF,#333333,(){this.inputNumber(9)})this.CalcButton(×,#FFFFFF,#FF9F0A,(){this.inputOperator(*)})}.width(100%).margin({bottom:12})Row(){this.CalcButton(4,#FFFFFF,#333333,(){this.inputNumber(4)})this.CalcButton(5,#FFFFFF,#333333,(){this.inputNumber(5)})this.CalcButton(6,#FFFFFF,#333333,(){this.inputNumber(6)})this.CalcButton(-,#FFFFFF,#FF9F0A,(){this.inputOperator(-)})}.width(100%).margin({bottom:12})Row(){this.CalcButton(1,#FFFFFF,#333333,(){this.inputNumber(1)})this.CalcButton(2,#FFFFFF,#333333,(){this.inputNumber(2)})this.CalcButton(3,#FFFFFF,#333333,(){this.inputNumber(3)})this.CalcButton(,#FFFFFF,#FF9F0A,(){this.inputOperator()})}.width(100%).margin({bottom:12})Row(){this.CalcButton(0,#FFFFFF,#333333,(){this.inputNumber(0)},2)this.CalcButton(.,#FFFFFF,#333333,(){this.inputNumber(.)})this.CalcButton(⌫,#FFFFFF,#333333,(){this.backspace()})this.CalcButton(,#FFFFFF,#FF9F0A,(){this.calculate()})}.width(100%)}.width(100%).padding(16).backgroundColor(Color.White).borderRadius(16).shadow({radius:8,color:#08000000,offsetX:0,offsetY:2})}.width(100%).height(100%).padding({left:18,right:18}).backgroundColor(#F5F7FA)}}八、代码实现说明1. 状态机设计计算器有几个关键状态初始状态显示0等待输入输入数字追加数字到display输入运算符保存当前值准备输入下一个数显示结果等于后显示结果下次输入数字时重置2. 连续运算点击运算符时如果已有运算符先计算之前的结果再保存新的运算符支持连续运算。3. 边界处理除以零显示Error多个小数点阻止输入第二个小数点开头的0输入第一个非0数字时替换0退格删到0就不再删了长数字自动截断避免溢出4. 按钮样式模仿iOS计算器风格数字键深灰背景白字功能键浅灰背景白字运算符橙色背景白字圆角按钮间距均匀5. 表达式显示计算时显示完整表达式让用户清楚看到计算过程。6. 结果格式化去掉浮点数计算产生的多余小数位避免显示类似0.30000000000000004的结果。九、运行项目代码编写完成后在DevEco Studio中运行项目。测试加减乘除运算测试小数、连续运算、清除、退格、正负、百分比等功能验证除以零的错误处理。十、开发中遇到的问题连续运算点击第二个运算符时要先计算前面的结果浮点数精度toFixed后转字符串去掉多余的0状态重置等于后输入新数字要重置显示按钮宽度0号键占两格宽度其他按钮等宽十一、总结本文基于HarmonyOS和ArkTS实现了一个标准计算器。项目通过状态机管理计算状态实现了完整的四则运算和各种计算器功能处理了各种边界情况。这个项目展示了ArkTS中状态管理、网格布局和逻辑处理的基本方法适合作为入门练习项目。