【鸿蒙应用开发 Dev ECO Stuidio 5.0版本】科学计算器 按钮动画 滑动删除 中缀表达式转后缀表达式(逆波兰表达式)附上完整项目及代码

本次博客基于下面博客

效果图

首先,先给大家看一下计算器的效果图

  • 以下是科学计算器的UI设计以及功能演示(附上手算答案),可见科学计算器计算功能没问题
    在这里插入图片描述在这里插入图片描述
  • 下面是演示视频以及退格设计:在计算式预览组件中滑动手指即可(左滑或者右滑)附上正确手算题目及答案
    在这里插入图片描述
    在这里插入图片描述

圆形按钮功能分析及代码(包含按钮动画)

按钮功能分析

  1. 点击后可以将这个按钮对应的字符添加到计算式字符串中(详见下面代码的OnClick事件)
  2. 点击时透明度发生变化以实现点击动效(详见下面代码的OnTouch事件)
  3. 在计算式的Row组件中手指滑动实现退格(退位)操作(详见下面代码的On)
  4. 外观和谐美观

代码

@Component
export struct Button1{
  //计算式
  @Link cal:string
  //计算结果
  @Link result:string|undefined|number
  //是否已经按下等号的标记
  @Consume flag:boolean
  //按钮透明度设置
  @Link button_opacity_son:number
  //1为测试数据
  num:string = '1'
  //按钮颜色
  buttonColor:number = 0x333333
  //文本颜色
  textColor:number = Color.White
  //文本大小
  textSize:number = 28

  build() {
   Column(){
     Text(`${this.num}`)
       .fontColor(this.textColor)
       .fontWeight(FontWeight.Medium)
       .fontSize(this.textSize)
   }.justifyContent(FlexAlign.Center)
   //按下按钮时,按钮的透明度改变
   .onTouch((Event:TouchEvent)=>{
     if(Event.type==TouchType.Down){
       this.button_opacity_son = 0.5
     }
     if(Event.type==TouchType.Up){
       this.button_opacity_son = 1;
     }
   })
    .width(80)
    .height(80)
    .opacity(this.button_opacity_son)
    .alignItems(HorizontalAlign.Center)
    .backgroundColor(this.buttonColor)
    .borderRadius(40)
    .onClick(()=>{
      //’AC‘功能的实现
      if(this.num=='AC'){
        this.flag = true;
        this.cal='';
        this.result = '0';
        return
      }
      else if(this.num=='='){
        //如果第一次按下等号就显示等号
        if(this.flag == true) {
          this.flag = false;
          let EndExpression =SwitchMiddleToEnd(this.cal);
          EndExpression.print_queue()
          this.result = calculate_achieve(EndExpression);
        }
        //否则不显示等号
        else {
          let EndExpression = SwitchMiddleToEnd(this.cal);
          EndExpression.print_queue()
          this.result = calculate_achieve(EndExpression);
          this.result = String(roundToDecimal(this.result));
        }
      }
      //将按钮所对应的字符加到计算式后
      else {
        this.cal += this.num;
      }
    })
}
}

滑动删除功能

滑动删除功能的实现原理思路

  1. 定义一个起始坐标(sta_x)、波尔类型的标记(flag==false)以及手指滑动过程中x坐标的偏移量(distance_x)
  2. 获得手指按下时的x坐标作为起始坐标(sta_x),并将flag改为true代表手指开始接触屏幕
  3. 手指滑动计算distance_x偏移量,如果偏移量大于某个值并且flag是true时就删除计算式字符串的最后一位,即实现退格操作,同时并把flag再次置为false使得如果不松手的话无论手指怎么滑动都只能进行一次退格。
  4. 手指离开时flag置为true,方便进行下一次滑动退格。

滑动删除功能代码

  Row() {
          Text(`${this.cal}`)
            .fontSize(24)
            .fontColor(Color.White)
        }.height(70)
        .width('100%')
        .justifyContent(FlexAlign.End)
        .padding({ right: 35 })
        //通过onTouch事件来实现滑动退格
        .onTouch((Event:TouchEvent)=>{
          if(Event.type==TouchType.Down){
          //获得手指按下时的x坐标作为起始坐标
            this.sta_x = Event.touches[0].x
            this.Delete_bool = true;
          }
          if(Event.type==TouchType.Up){
              this.Delete_bool = true
          }
          if(Event.type==TouchType.Move){
          //移动过程中计算x轴上移动的距离
              this.distance_x = Math.abs(this.sta_x - Event.touches[0].x)
          //如果距离超过20就进行退格操作
            if(this.distance_x>20&&this.Delete_bool == true){
             this.cal = this.cal.slice(0,-1);
             this.Delete_bool = false;
            }
          }
        })

中缀表达式转后缀表达式(逆波兰表达式)

实现思路原理

  • 规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;若是符号,则判断其与栈顶符号的优先级,是右括号或者优先级不高于栈顶符号(乘除优先加减)则栈顶元素依次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止。
  • 做法:我们这里分别构造了一个队列和一个栈,栈根据以上规则进行获得后缀表达式,而队列用来存储后缀表达式,最后将这个存储着后缀表达式的队列返回。关于栈和队列的构建可以看下面两个博客:

代码实现

//中缀表达式转后缀表达式函数
export function SwitchMiddleToEnd(cal:string){
  let queue = new queue_my();
  let first_fu:boolean = true
  let switchStack = new CharacterStack();
  let i =0;
  let currentcharacter:string = '';
  let flaglog:boolean = false;
  let flagtriangle:boolean = false;
  while(i<cal.length){
    if(isCharacter(cal[i])){
      currentcharacter = cal[i];
      console.log('当前的符号为:'+currentcharacter);
    }
    else if(cal[i]=='l'){
      currentcharacter = 'l'+cal[i+1];
      console.log('当前的符号为:'+currentcharacter);
      flaglog = true;
    }
    else if(isSingleCharacter1(cal[i])&&cal[i]!='l'){
      currentcharacter = cal[i]+cal[i+1]+cal[i+2];
      console.log('当前的符号为:'+currentcharacter);
      flagtriangle = true;
    }


    //如果遍历到数字直接入队
    if(isNumber(cal[i])){
      let numberstring = '';
      if(cal[i]=='π'){
        queue.enqueue(String(Math.PI));
      }
      else {
        while (isNumber(cal[i])) {
          numberstring += cal[i];
          i++
        }
        queue.enqueue(numberstring);

        console.log(`${numberstring}入队`);
        i--
      }
    }
    //如果遇到第一个位置是左括号加-号
      else if(cal[0]=='('&&cal[1]=='-'&&first_fu){
        switchStack.push(cal[0]);
        let numberstring = '-'
        first_fu = false;
        i = 2
        while(isNumber(cal[i])){
          numberstring+=cal[i]
          i++
        }
        queue.enqueue(numberstring)
      i--
      console.log(`${numberstring}入队`);
      console.log(`此时遍历到了:${cal[i]}`)
    }

    else if(cal[0]=='-'&&isNumber(cal[1])&&first_fu){
      let numberstring = '-';
      first_fu = false;
      i=1;
      while(isNumber(cal[i])){
        numberstring+=cal[i];
        i++
      }
      queue.enqueue(numberstring);
      console.log(`${numberstring}入队`);
      i--;
    }
    //如果连按几次同一个操作符
     /* else if(!isNumber(cal[i])&&!isNumber(cal[i+1])&&cal[i]==cal[i+1]){
        i++;
    }*/
    //带括号的负数在中间的时候
      else if(cal[i]=='('&&cal[i+1]=='-'&&isNumber(cal[i+2])){
      let numberstring = '-';
      i = i+2;
      while(isNumber(cal[i])){
        numberstring+=cal[i];
        ++i
      }
      queue.enqueue(numberstring)
      console.log(`${numberstring}已经入队`)
    }

    //如果栈中为空或者遇到左括号直接入栈
    else if(switchStack.isEmpty()||cal[i]=='('){
      if(cal[i]=='(') console.log('遇到了左括号')
      switchStack.push(currentcharacter);
    }
    //栈顶操作符优先级小于当前操作符优先级
    else if(cal[i]!=')'&&getPrecedence(switchStack.peek())<getPrecedence(currentcharacter)){
      switchStack.push(currentcharacter);
      console.log("放入的操作符为:"+currentcharacter);
    }
    //栈顶操作符优先级大于当前操作符优先级
    else if(cal[i]!=')'&&getPrecedence(switchStack.peek())>=getPrecedence(currentcharacter)){
        //栈顶元素出栈并且加到队列中去
        while(getPrecedence(currentcharacter)<=getPrecedence(switchStack.peek()))
        {queue.enqueue(String(switchStack.pop()))
          if(switchStack.isEmpty()){break}
        }
        switchStack.push(currentcharacter);
    }
    //如果遇到了右括号
    else if(currentcharacter==')') {
      console.log('遇到了右括号')
      while (switchStack.peek() != '(') {
        let temp: string = String(switchStack.pop());
        queue.enqueue(temp);
      }
      //遇到左括号时直接将左括号弹出
      switchStack.pop()
     // console.log('左括号出栈')
    }
    if(flaglog){
      i = i+2;
      flaglog = false;
    }
    else if(flagtriangle){
      i = i+3;
      flagtriangle = false;
    }
    else {
      i++;
    }
    console.log('现在的i为:'+i);
  }
  //最后将剩余的操作符全部放到队列中
  while(!switchStack.isEmpty()) {
    queue.enqueue(String(switchStack.pop()))
  }
  queue.print_queue()
  return queue;
}


完成代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值