【鸿蒙开发案例篇】鸿蒙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下基于基础组件的计算器开发,重点解决了浮点数精度和大数显示等核心问题。兄弟们,可以去试试哦。

相关推荐
威哥爱编程2 小时前
【鸿蒙开发案例篇】鸿蒙跨设备实时滤镜同步的完整方案
harmonyos·arkts·arkui
L、2184 小时前
统一日志与埋点系统:在 Flutter + OpenHarmony 混合架构中实现全链路可观测性
javascript·华为·智能手机·electron·harmonyos
hefengbao6 小时前
『京墨文库』鸿蒙版上线!
harmonyos·arkts·arkui·arkdata
赵浩生6 小时前
鸿蒙技术干货6:鸿蒙权限管理与后台任务开发指南(下)
harmonyos
赵浩生6 小时前
鸿蒙技术干货5:鸿蒙权限管理与后台任务开发指南(上)
harmonyos
kirk_wang7 小时前
Flutter插件跨平台适配技术分析之是否需要适配鸿蒙端-screenshot
flutter·华为·harmonyos
kirk_wang7 小时前
Flutter path_provider 在 OpenHarmony 平台上的实现与适配实践
flutter·移动开发·跨平台·arkts·鸿蒙
赵财猫._.8 小时前
React Native鸿蒙开发实战(七):性能优化与调试技巧
react native·性能优化·harmonyos
晚霞的不甘9 小时前
[鸿蒙2025领航者闯关] Flutter + OpenHarmony 模块化架构设计:大型应用的可维护性与协作之道
flutter·华为·harmonyos·鸿蒙·鸿蒙系统