【鸿蒙开发案例篇】鸿蒙6.0计算器实现详解

大家好,我是 V 哥。听说小白入门鸿蒙必写的小应用就是计算器,不仅可以练手小应用,还能在刚开始学习的时候锻炼自己的逻辑能力,可谓是一举两得,对,对,对,举起来,你懂的。

下面是基于基础组件和容器组件来练练手,V哥将详细实现一个支持加减乘除混合运算的计算器。

联系V哥获取 鸿蒙学习资料


一、项目结构与核心设计

技术栈

  • API版本:HarmonyOS 6.0.0 Release (API 21)
  • 开发工具:DevEco Studio 6
  • 核心组件:TextInput、Button、ForEach、Grid、Stack

目录结构

bash 复制代码
Calculator/
├── entry/
│   └── src/
│       ├── main/
│       │   ├── ets/
│       │   │   ├── pages/
│       │   │   │   └── Index.ets        # 主页面
│       │   │   ├── utils/
│       │   │   │   └── Calculator.ts    # 计算逻辑
│       │   │   └── CommonConstants.ts   # 常量定义
│       │   └── resources/               # 资源文件

二、核心代码实现

1. 常量定义(CommonConstants.ts)

typescript 复制代码
export class CommonConstants {
  // 运算符常量
  static readonly ADD: string = '+';
  static readonly SUB: string = '-';
  static readonly MUL: string = '×';
  static readonly DIV: string = '÷';
  static readonly EQUAL: string = '=';
  static readonly CLEAR: string = 'C';
  static readonly BACKSPACE: string = '⌫';
  static readonly DOT: string = '.';
  
  // 按钮布局
  static readonly BUTTONS: string[][] = [
    ['C', '⌫', '÷', '×'],
    ['7', '8', '9', '-'],
    ['4', '5', '6', '+'],
    ['1', '2', '3', '='],
    ['0', '.', '=']
  ];
}

2. 计算逻辑核心(Calculator.ts)

typescript 复制代码
export class Calculator {
  private currentInput: string = '0';
  private previousInput: string = '';
  private operator: string = '';
  private shouldResetInput: boolean = false;

  // 处理按钮点击
  handleButtonClick(button: string): string {
    if (this.isNumber(button)) {
      return this.handleNumber(button);
    } else if (this.isOperator(button)) {
      return this.handleOperator(button);
    } else if (button === CommonConstants.DOT) {
      return this.handleDot();
    } else if (button === CommonConstants.CLEAR) {
      return this.handleClear();
    } else if (button === CommonConstants.BACKSPACE) {
      return this.handleBackspace();
    } else if (button === CommonConstants.EQUAL) {
      return this.handleEqual();
    }
    return this.currentInput;
  }

  // 数字处理(解决精度问题)
  private handleNumber(num: string): string {
    if (this.shouldResetInput || this.currentInput === '0') {
      this.currentInput = num;
      this.shouldResetInput = false;
    } else {
      this.currentInput += num;
    }
    return this.currentInput;
  }

  // 运算符处理
  private handleOperator(op: string): string {
    if (this.operator && !this.shouldResetInput) {
      this.calculate();
    }
    this.previousInput = this.currentInput;
    this.operator = op;
    this.shouldResetInput = true;
    return this.currentInput;
  }

  // 等于号处理
  private handleEqual(): string {
    if (this.operator && this.previousInput) {
      this.calculate();
      this.operator = '';
      this.shouldResetInput = true;
    }
    return this.currentInput;
  }

  // 核心计算逻辑(解决浮点数精度问题)
  private calculate(): void {
    const prev = parseFloat(this.previousInput);
    const current = parseFloat(this.currentInput);
    
    if (isNaN(prev) || isNaN(current)) return;

    let result: number;
    switch (this.operator) {
      case CommonConstants.ADD:
        // 小数精度处理:转换为整数计算
        result = this.add(prev, current);
        break;
      case CommonConstants.SUB:
        result = this.subtract(prev, current);
        break;
      case CommonConstants.MUL:
        result = this.multiply(prev, current);
        break;
      case CommonConstants.DIV:
        result = this.divide(prev, current);
        break;
      default:
        return;
    }
    
    // 处理大数显示(科学计数法)
    this.currentInput = this.formatResult(result);
  }

  // 精确加法(解决0.1+0.2≠0.3问题)
  private add(a: number, b: number): number {
    const multiplier = Math.pow(10, Math.max(this.getDecimalLength(a), this.getDecimalLength(b)));
    return (a * multiplier + b * multiplier) / multiplier;
  }

  // 精确乘法
  private multiply(a: number, b: number): number {
    const decimalLength = this.getDecimalLength(a) + this.getDecimalLength(b);
    const multiplier = Math.pow(10, decimalLength);
    return (a * Math.pow(10, this.getDecimalLength(a))) * 
           (b * Math.pow(10, this.getDecimalLength(b))) / multiplier;
  }

  // 获取小数位数
  private getDecimalLength(num: number): number {
    const str = num.toString();
    return str.includes('.') ? str.split('.').length : 0;
  }

  // 结果格式化(大数转科学计数法)
  private formatResult(result: number): string {
    if (Math.abs(result) > 1e15 || (Math.abs(result) < 1e-6 && result !== 0)) {
      return result.toExponential(10).replace(/(\.\d*?[1-9])0+e/, '$1e');
    }
    return result.toString();
  }

  // 其他辅助方法
  private isNumber(str: string): boolean { return !isNaN(Number(str)); }
  private isOperator(str: string): boolean { 
    return [CommonConstants.ADD, CommonConstants.SUB, CommonConstants.MUL, CommonConstants.DIV].includes(str); 
  }
  private handleDot(): string { /* 实现小数点逻辑 */ }
  private handleClear(): string { /* 实现清空逻辑 */ }
  private handleBackspace(): string { /* 实现退格逻辑 */ }
  private subtract(a: number, b: number): number { /* 精确减法 */ }
  private divide(a: number, b: number): number { /* 精确除法 */ }
}

3. 主页面UI实现(Index.ets)

typescript 复制代码
@Entry
@Component
struct CalculatorPage {
  @State displayText: string = '0'
  private calculator: Calculator = new Calculator()

  build() {
    Column({ space: 20 }) {
      // 显示区域
      TextInput({ text: this.displayText })
        .width('90%')
        .height(80)
        .fontSize(32)
        .textAlign(TextAlign.End)
        .backgroundColor(Color.White)
        .border({ width: 2, color: Color.Blue })

      // 按钮区域 - 使用Grid布局
      Grid() {
        ForEach(CommonConstants.BUTTONS, (row: string[], rowIndex: number) => {
          GridItem() {
            Row({ space: 10 }) {
              ForEach(row, (button: string) => {
                Button(button)
                  .width(70)
                  .height(70)
                  .fontSize(24)
                  .fontColor(this.getButtonColor(button))
                  .backgroundColor(this.getButtonBgColor(button))
                  .borderRadius(10)
                  .onClick(() => {
                    this.onButtonClick(button)
                  })
              })
            }
          }
        })
      }
      .columnsTemplate('1fr 1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr 1fr 1fr 1fr')
      .width('90%')
      .height(400)
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .backgroundColor('#F5F5F5')
  }

  // 按钮点击处理
  private onButtonClick(button: string): void {
    this.displayText = this.calculator.handleButtonClick(button)
  }

  // 按钮颜色配置
  private getButtonColor(button: string): Color {
    if (this.isOperator(button) || button === CommonConstants.EQUAL) {
      return Color.White
    }
    return Color.Black
  }

  private getButtonBgColor(button: string): Color {
    if (button === CommonConstants.CLEAR) {
      return Color.Red
    } else if (this.isOperator(button) || button === CommonConstants.EQUAL) {
      return Color.Blue
    }
    return Color.White
  }

  private isOperator(button: string): boolean {
    return [CommonConstants.ADD, CommonConstants.SUB, CommonConstants.MUL, CommonConstants.DIV].includes(button)
  }
}

三、关键技术特性

1. 精度处理机制

typescript 复制代码
// 示例:0.2 + 2.22 的正确计算
private add(a: number, b: number): number {
  const decimalA = this.getDecimalLength(a)  // 1位小数
  const decimalB = this.getDecimalLength(b)  // 2位小数
  const multiplier = Math.pow(10, Math.max(decimalA, decimalB))  // 100
  
  return (a * multiplier + b * multiplier) / multiplier
  // 计算过程:(0.2*100 + 2.22*100)/100 = (20 + 222)/100 = 242/100 = 2.42
}

2. 大数显示优化

typescript 复制代码
// 9007199254740992 + 1 显示为科学计数法
private formatResult(result: number): string {
  if (result > 1e15) {
    return result.toExponential(10)  // &#34;9.007199254740993e15&#34;
  }
  return result.toString()
}

3. 连续运算支持

  • 支持表达式:3 + 5 × 2 - 1 = 12
  • 状态管理:通过previousInputcurrentInputoperator跟踪运算状态

四、运行效果与测试用例

测试场景

  1. 基础运算5 + 3 = 8
  2. 小数精度0.1 + 0.2 = 0.3
  3. 混合运算3 + 5 × 2 = 13
  4. 大数处理999999999999999 + 1 = 1e+15
  5. 错误处理5 ÷ 0 = Infinity

五、扩展功能建议

  1. 历史记录:添加Stack组件保存计算历史
  2. 主题切换:使用@StorageLink实现深色模式
  3. 语音播报:集成TTS功能朗读计算结果
  4. 单位转换:扩展科学计算器功能

这个实现完整展示了鸿蒙6.0下基于基础组件的计算器开发,重点解决了浮点数精度和大数显示等核心问题。兄弟们,可以去试试哦。

相关推荐
nashane1 小时前
HarmonyOS 6学习:CapsLock键失效诊断与长截图完整实现指南
学习·华为·harmonyos
richard_yuu3 小时前
鸿蒙心理测评模块实战|PHQ-9/GAD7双量表答题、实时计分与结果本地化存储
华为·harmonyos
不爱吃糖的程序媛6 小时前
2026年Electron 鸿蒙PC环境搭建指南
人工智能·华为·harmonyos
nashane6 小时前
HarmonyOS 6学习:长截图功能开发中的滚动拼接与权限处理实战
人工智能·华为·harmonyos
大师兄66687 小时前
从零开发一个 HarmonyOS 输入法——KikaInputMethod 完整拆解
harmonyos·服务卡片·harmonyos6·formkit
Python私教13 小时前
鸿蒙 NEXT 也能接 MCP?用 ArkTS 跑通 AI Agent 工具链
人工智能·华为·harmonyos
Swift社区15 小时前
分布式能力在鸿蒙 PC 上到底怎么用?
分布式·华为·harmonyos
nashane1 天前
HarmonyOS 6学习:外接键盘CapsLock与长截图功能的实战调试与完整解决方案
学习·华为·计算机外设·harmonyos
aqi001 天前
一文理清 HarmonyOS 6.0.2 涵盖的十个升级点
android·华为·harmonyos·鸿蒙·harmony