HarmonyOS NEXT 教程:ArkTS 实现简易计算器 App 实例
- 作者: 刘杰
- 来源: 技术那些事
- 阅读:301
- 发布: 2025-07-10 06:44
- 最后更新: 2025-08-22 15:16
计算器项目详细设计
以下是一个基于 HarmonyOS NEXT 的简易计算器 App 实例,涵盖 UI 布局、事件处理和基础计算逻辑,帮助开发者快速上手鸿蒙应用开发:
一、项目创建与结构
-
新建项目(SimpleCalculator) 在 DevEco Studio 中选择 “Create Project”,模板选 “Empty Ability”,Language 选择 “ArkTS”,项目名为
SimpleCalculator。 -
项目结构说明
plaintextSimpleCalculator/ ├── entry/ # 主模块 │ ├── src/ │ │ ├── main/ │ │ │ ├── ets/ # ArkTS源码目录 │ │ │ │ ├── pages/ # 页面文件夹 │ │ │ │ │ └── index.ets # 主页面 │ │ │ ├── resources/ # 资源文件 │ │ └── module.json5 # 模块配置 └── build-profile.json5 # 构建配置
二、UI 布局与逻辑实现
1. index.ets 页面代码
typescript
// entry/src/main/ets/pages/index.ets
import promptAction from '@ohos.promptAction';
@Entry
@Component
struct Index {
// 状态管理:存储计算表达式和结果
@State expression: string = '0'
@State result: string = '0'
@State isNewInput: boolean = true // 标记是否开始新输入
// 数字按钮点击处理
handleNumberClick(num: string) {
if (this.isNewInput) {
// 新输入时覆盖当前显示
this.expression = num
this.isNewInput = false
} else {
// 追加数字
this.expression = this.expression === '0' ? num : this.expression + num
}
}
// 运算符按钮点击处理
handleOperatorClick(operator: string) {
if (this.isNewInput) return;
// 避免重复点击运算符
if (['+', '-', '*', '/'].includes(this.result)) {
this.result = operator
return
}
// 计算当前表达式并更新结果
this.result = this.calculate(this.expression, this.result)
this.expression = this.result
this.result = operator
this.isNewInput = true
}
// 等号按钮处理(计算最终结果)
handleEqualClick() {
if (this.isNewInput || !this.result) return;
this.result = this.calculate(this.expression, this.result)
this.expression = this.result
this.isNewInput = true
this.result = ''
}
// 清除按钮处理
handleClearClick() {
this.expression = '0'
this.result = '0'
this.isNewInput = true
}
// 计算函数
calculate(num1: string, operator: string): string {
const num = parseFloat(num1)
switch (operator) {
case '+': return (parseFloat(this.result) + num).toString()
case '-': return (parseFloat(this.result) - num).toString()
case '*': return (parseFloat(this.result) * num).toString()
case '/':
if (num === 0) {
promptAction.showToast({ message: '除数不能为0' })
return this.result
}
return (parseFloat(this.result) / num).toString()
default: return num.toString()
}
}
build() {
Column() {
// 显示区域
Stack() {
Text(this.expression)
.fontSize(48)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.End)
.width('100%')
.margin(16)
.foregroundColor('#000000')
}
.height(120)
.width('100%')
.backgroundColor('#F5F5F5')
.marginBottom(16)
// 按钮区域 - 4x4网格
Grid() {
// 第一行:C(清除)、±(正负)、%(百分比)、÷(除法)
GridItem() {
Button('C')
.width(80)
.height(80)
.backgroundColor('#E0E0E0')
.onClick(() => this.handleClearClick())
}
GridItem() {
Button('±')
.width(80)
.height(80)
.backgroundColor('#E0E0E0')
}
GridItem() {
Button('%')
.width(80)
.height(80)
.backgroundColor('#E0E0E0')
}
GridItem() {
Button('÷')
.width(80)
.height(80)
.backgroundColor('#FF9500')
.onClick(() => this.handleOperatorClick('/'))
}
// 第二行:7、8、9、×(乘法)
GridItem() {
Button('7')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('7'))
}
GridItem() {
Button('8')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('8'))
}
GridItem() {
Button('9')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('9'))
}
GridItem() {
Button('×')
.width(80)
.height(80)
.backgroundColor('#FF9500')
.onClick(() => this.handleOperatorClick('*'))
}
// 第三行:4、5、6、-(减法)
GridItem() {
Button('4')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('4'))
}
GridItem() {
Button('5')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('5'))
}
GridItem() {
Button('6')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('6'))
}
GridItem() {
Button('-')
.width(80)
.height(80)
.backgroundColor('#FF9500')
.onClick(() => this.handleOperatorClick('-'))
}
// 第四行:1、2、3、+(加法)
GridItem() {
Button('1')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('1'))
}
GridItem() {
Button('2')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('2'))
}
GridItem() {
Button('3')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('3'))
}
GridItem() {
Button('+')
.width(80)
.height(80)
.backgroundColor('#FF9500')
.onClick(() => this.handleOperatorClick('+'))
}
// 第五行:0、.(小数点)、=(等号)
GridItem() {
Button('0')
.width(180)
.height(80)
.backgroundColor('#F0F0F0')
.onClick(() => this.handleNumberClick('0'))
}
GridItem() {
Button('.')
.width(80)
.height(80)
.backgroundColor('#F0F0F0')
}
GridItem() {
Button('=')
.width(80)
.height(80)
.backgroundColor('#FF9500')
.onClick(() => this.handleEqualClick())
}
}
.columnsTemplate('1fr 1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr 1fr 1fr')
.width('100%')
.height('100%')
}
.width('100%')
.height('100%')
.padding(16)
.backgroundColor('#FFFFFF')
}
}
三、功能说明
1. 状态管理
-
@State expression:显示当前输入的数字或表达式(如 “123+45”)。 -
@State result:存储运算符和中间计算结果(如 “+”“123”)。 -
@State isNewInput:标记是否开始新的数字输入(避免连续输入时覆盖前导零)。
2. 核心逻辑
-
数字输入:点击数字按钮时,根据
isNewInput状态决定是覆盖还是追加数字。 - 运算符处理:点击运算符(+/-/*//)时,触发当前表达式计算,并更新结果状态。
-
等号计算:调用
calculate函数完成最终运算,处理除数为 0 等异常情况。 - 清除功能:重置所有状态,回到初始界面。
3. UI 布局
- 采用
Column垂直布局,上部分为表达式显示区(Stack容器),下部分为按钮区(Grid网格布局)。 - 按钮区按 4x5 网格排列,运算符按钮使用橙色背景(
#FF9500)区分,数字按钮使用浅灰色(#F0F0F0)。
四、运行与测试
- 启动模拟器 点击 DevEco Studio 右上角的 “Device Manager”,选择 HarmonyOS 模拟器(如 Phone API 9+),点击 “Run” 按钮启动应用。
-
功能测试
- 输入数字 “123”,点击 “+”,再输入 “45”,点击 “=”,应显示结果 “168”。
- 点击 “C” 按钮,确认表达式和结果重置为 “0”。
- 尝试输入 “0÷0”,确认提示 “除数不能为 0”。
五、扩展方向
-
分布式能力:在
handleEqualClick中添加跨设备计算逻辑,例如:typescript// 调用远程设备(如平板)进行复杂计算 import distributedData from '@ohos.distributedData'; // ... distributedData.callRemoteService({ deviceId: 'targetDeviceId', serviceName: 'calculatorService', method: 'complexCalculate', args: [this.expression, this.result] }).then((res) => { this.expression = res.result }); -
UI 优化:添加按钮点击动画效果:
typescriptButton('7') .width(80) .height(80) .backgroundColor('#F0F0F0') .onClick(() => { this.handleNumberClick('7') }) .stateEffect(StateEffect.Scale(1.1, 1.1, 300)) // 点击缩放动画
通过这个实例,开发者可快速掌握 HarmonyOS NEXT 的状态管理、UI 布局和事件处理机制,进一步可结合分布式能力实现跨设备协同功能。