当前位置: 首页 > news >正文

Android学习之计算器app(java + 详细注释 + 源码)

运行结果:

基础的四则运算:

可能会出现的问题以及解决方法:

 问题1:出现多个操作符。

例子:1++++++2

解决方法:

在用户点击操作符之后,去检查之前的最后一位,如果最后一位也是操作符的话,就进行替代操作。

问题2:小数点问题。

例子:0......1  以及 .2

解决方法:

对于0.....1的问题,用的是一个全局变量 addPoint,当它为true的时候才可以进行添加小数点操作。

当点击 π 或者是 小数点之后 就要把 addPoint 置为false,也即表示不能再去添加小数点了。

当点击操作符或者是C(清空)之后就要把 addPoint 置为false,也即表示可以再去添加小数点了。

问题3:非法操作。

例子:

1:除0

2:阶乘溢出

3:负数开根号

4:logx, 其中x <= 0

5:(0.123)!

6:(-3)!

解决方法:

对每个运算进行提前监控,如果出现违规操作要把用户的除了C(清空)按钮外全部禁掉,然后做出违规提示,参考Win11自带计算器。但是感觉更加规范的是 可以自定义异常 然后去对应到每一个的异常处理问题。

问题4:负数的复杂性

例子:-3 对这个实现起来还是比较麻烦的

解决方法:

对这个不进行特殊判断,还是点击 "-" 之后看看它的前面有没有数字,如果没有的话,也去补上0, 这个0是默认的。

新增括号功能:

对括号进行了显示,以及可以进行括号运算

在界面显示出右括号和左括号的数量,而且右括号的数量数不能多于左括号的,参照win11自带计算器。

可能出现的问题以及解决方法:

问题1:出现 (+)。

也即是括号里面只有操作符。

解决的方法:

1:当点击运算符的时候,检查它的前面是不是 "(", 如果是的话就去自动去补0

2:当点击 "(" 的时候,去检查它的前面是不是 操作符,如果是的话就去自动补0

问题2:出现(0)(0)这样的情况。
解决方法:

当用户点击 "(" 的时候去校验当前已经存在的字符串的最后一位,如果它不是操作符的话,就去指定去补上一个操作符,我在这里默认的是 "x"。

问题3:出现0 + (-3) + 5 这样的情况。
解决方法:

当用户点击操作符的时候,就去检测当前已经存在的最后一个字符是不是数字,如果不是数字的话,就去补上一个默认的0,但是还会出现这样的情况0 + (0 - 3) 0 + 3,它把0补到了这里了,这里再去加一个特殊的判断,如果最后一个是 ")" 就不去加上这个默认的0。但是改为之后又出现了这样的情况:0+(0)------------,解决的方法当这个最后一个字符是 "(" 的时候再去增加默认的0。  

声明:

因为作者是一个考研dog,so 没有足够的时间去写这个,只能晚上10回去之后加班写,或者在其他老师课上写,因此间隔时间比较大,而且逻辑比较乱,希望大家多多包涵。 

计划:

1:后期可以去增加一个 按键声音的功能,也即是你点击一个按钮之后,就会产生特定的生硬,当然声音是作者自己那美妙的声音。(已经实现,用的是在线生成的ai女声)。

2:增加登录操作,把每个人的计算的操作给记录下来,可以查看自己历史计算记录

java代码:

package com.findyou.myapplication;import android.content.Context;
import android.media.AudioAttributes;
import android.media.AudioManager;
import android.media.SoundPool;
import android.os.Bundle;
import android.view.SoundEffectConstants;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;import java.math.BigInteger;
import java.util.HashMap;
import java.util.Objects;
import java.util.Stack;public class Test_jsq extends AppCompatActivity implements View.OnClickListener {private TextView tv_result, show_kh; // 获取文本框的内容 为了进行设置// 第一个操作数// 第二个操作数// 运算符private String operator = "";// 结果private String result = "";// 显示的文本内容 刚开始的时候要显示的是 0private String showText = "0"; // 3+2private Boolean addPoint = true;private boolean denominatorIsZero = false; // 分母是否为0private final String ISZERO = "分母不可为0!";private final String FACTORIALERROR = "小数和分数没有阶乘,阶乘只在自然数中进行";private final String OVERFLOW = "溢出";private final String NAGATIVE_HAS_NO_FACTORIAL = "负数没有阶乘";private final String NAGATIVE_HAS_NO_SQRT = "根号下要大于等于0";private final String LN_NEED_GREATER_THAN_ZERO = "ln里面需要大于0";private final String LON_NEED_GREATER_THAN_ZERO = "log里面需要大于0";// 新增加的 左右括号的显示操作 初始化的括号的数量都显示为 0private int leftParenthesis = 0, rightParenthesis = 0;// 以下是增加的声音的功能// 定义一个全局的变量 看看用户想不想去播放音效private Boolean play = true; // 表示的是 可以去播放音效private int currentId; // 为了记录当前点击了那个声音了,是为了方便后面的暂停SoundPool sp; // 声明SoundPool的引用HashMap<String, Integer> hm; // 声明HashMap来存放声音文件@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_calculator);initSoundPool(); // 初始化声音池的方法// 获取tv_result ctrl + alt + f 变为全局变量tv_result = findViewById(R.id.tv_result);show_kh = findViewById(R.id.show_kh); // 对括号的截取和显示Button btn_cancel = findViewById(R.id.btn_cancel);btn_cancel.setOnClickListener(this);Button btn_sy = findViewById(R.id.sy);btn_sy.setOnClickListener(this);// 给每个按钮设置监听findViewById(R.id.btn_cancel).setOnClickListener(this);findViewById(R.id.btn_divide) .setOnClickListener(this);//“除法"按钮findViewById(R.id.btn_multiply).setOnClickListener(this); // "乘法"按钮findViewById(R.id.btn_clear) .setOnClickListener(this);findViewById(R.id.btn_seven).setOnClickListener(this); // 数字7findViewById(R.id.btn_eight).setOnClickListener(this); // 数字8findViewById(R.id.btn_nine).setOnClickListener(this); // 数字9findViewById(R.id.btn_plus) .setOnClickListener(this) ;findViewById(R.id.btn_four).setOnClickListener(this); // 数字4findViewById(R.id.btn_five).setOnClickListener(this); // 数字5findViewById(R.id.btn_six) .setOnClickListener(this); // 数字6findViewById(R.id.btn_minus).setOnClickListener(this);// "减法"按钮findViewById(R.id.btn_one).setOnClickListener(this); // 数字1findViewById(R.id.btn_two).setOnClickListener(this); // 数字2findViewById(R.id.btn_three).setOnClickListener(this); // 数字3findViewById(R.id.btn_reciprocal).setOnClickListener(this);// 求倒数按钮findViewById(R.id.btn_zero).setOnClickListener(this); // 数字0findViewById(R.id.btn_dot).setOnClickListener(this);// “小数点"按钮findViewById(R.id.btn_equal).setOnClickListener(this);// "等号"按钮findViewById(R.id.btn_sqrt) .setOnClickListener(this) ;// 开根号按钮findViewById(R.id.btn_PI).setOnClickListener(this); // π按钮的监听findViewById(R.id.btn_factorial).setOnClickListener(this); // 阶乘按钮的监听findViewById(R.id.btn_e).setOnClickListener(this); // e 按钮的监听findViewById(R.id.btn_abs).setOnClickListener(this); // 绝对值 按钮的监听// 新增加的功能findViewById(R.id.btn_left_kh).setOnClickListener(this); // 对左括号 按钮进行监听findViewById(R.id.btn_right_kh).setOnClickListener(this); // 对右括号 按钮进行监听findViewById(R.id.btn_log).setOnClickListener(this); // 对 log 按钮 进行监听findViewById(R.id.btn_ln).setOnClickListener(this); // 对 ln 按钮进行监听}// 变为公用的@Overridepublic void onClick(View v) {if(v.getId() == R.id.sy) {if(play) { // 要去关闭声音了findViewById(R.id.sy).setBackground(ContextCompat.getDrawable(this, R.drawable.close));play = false;} else {findViewById(R.id.sy).setBackground(ContextCompat.getDrawable(this, R.drawable.open));play = true;}return;}// 测试 是否能正常显示在界面 很好奇 为什么这个 测试的 没有 ban 掉// tv_result.setText(((TextView) v).getText().toString());String inputText;// 如果是开根号的按钮if (v.getId() == R.id.btn_sqrt) {inputText = "√";} else {inputText = ((TextView) v).getText().toString();}if(sp != null && currentId != 0) {sp.stop(currentId); // 立马停止当前正在播放的声音}if(play && !inputText.equals("=")) {// 点击之后 开始在这里播放音乐playSound(inputText);}int t = v.getId();// 点击了清空按钮if (t == R.id.btn_clear) {// 清空的时候 要去恢复按钮illegal(true);// 注意二者顺序clear();// 也要去清空括号clearKh();} else if(t ==  R.id.btn_cancel) { // 后退按钮// 注意 后退 是 不能 去进行 后退 操作符号 的showText = Backoff(showText);if(Objects.equals(showText, "")) {showText = "0"; // 最后一个都被清空了}// 刷新文本refreshText(showText);} else if(t == R.id.btn_plus || t == R.id.btn_minus || t == R.id.btn_multiply || t == R.id.btn_divide){ // 点击了 加 减 乘 除//  如果操作符的前面是小数点的话 就要把小数点给省略掉 0.1 - 0. + ---> 0.1 - 0 +addPoint = true; // 把小数点可以更新了operator = inputText;char temp = showText.charAt(showText.length() - 1);// 每当进行 加减操作的时候 先去看看它的最后一个是不是有效的 不是有效的话 要去主动去增加一个 0  无论是小数点还是普通的加减// 增加的 这一个 可能出现了问题了//            if(!checkIsNum(showText.charAt(showText.length() - 1)) && temp != '(' && temp != ')') {
//                showText = showText + "0";
//            }// 这里防止出现这样的情况: (+0)的情况
//            if(checkIskh(temp)) {
//                showText = showText + "0";
//            }// 检查前面的最后一项是不是数字 如果不是数字的话 就去补上一个默认的0if(!checkIsNum(temp) && temp != ')' && !checkIsOp(temp)) {showText += "0";}// 查看当前这个字符串的最后一个 也是操作符的话 就把它给覆盖掉if(checkIsOp(temp)) {// 就把当前的字符串的最后一个给替换掉showText = showText.substring(0, showText.length() - 1) + operator;refreshText(showText);} else {// 这里解决的是 0.-3 这样的问题 解决的方法是把 小数点给去掉if(showText.charAt(showText.length() - 1) == '.') {showText = showText.substring(0, showText.length() - 1);}refreshText(showText + operator);}//  等号 的操作} else if(t == R.id.btn_equal) { // 等号按钮// 进行规格化String ret = Normalized(js(showText));refreshText(ret);// 计算的结果要去循环的去播放出来playRet(ret);// 前提是没有小数点的话 再去恢复if(!ret.contains(".")) {// 等号的话 也要去恢复小数点的操作addPoint = true;}clearKh();// 然后去清空掉
//            showText = "0";//1 + 0123.0 √} else if(t == R.id.btn_sqrt) { // 开根号js3(1); // 1 表示的是开根号的操作} else if(t == R.id.btn_reciprocal) { // 求倒数js3(2);} else if(t == R.id.btn_PI)  { // 点击了 π 的 操作js3(4);} else if(t == R.id.btn_factorial) { // 点击了阶乘的操作js3(3);} else if(t == R.id.btn_abs) {js3(5); // 点击了绝对值的操作} else if(t == R.id.btn_e) { // 点击的是 e 的 操作js3(6);} else if(t == R.id.btn_ln) { // 点击的是 ln 的操作js3(7);} else if(t == R.id.btn_log) { // 点击的是 log 的操作js3(8);}else if(t == R.id.btn_left_kh) {leftParenthesis ++ ;// 刷新 界面的括号显示数字 并且把 括号给拼接上去// 这里也要特判一下 可能存在 这样的情况 比如: (0)() 要把它变成 (0)x(0) 这样的情况char pre = showText.charAt(showText.length() - 1);if(pre == ')') {showText += 'x';}// 这里需要去校验一种情况是 1( 要把它变为 1 + (这样的形式if(checkIsNum(pre)) {showText += "+";}refreshText(showText + inputText);} else if(t == R.id.btn_right_kh) { // 点击了右括号// 为了让他们进行匹配 也即是 存在 对应的左括号的时候才进行匹配if(rightParenthesis < leftParenthesis) {rightParenthesis ++ ;// 刷新 界面的右括号显示数字 并且把括号给拼接上去// 这里要单独去检验一下 可能是 () 这样的情况是不允许的 要去在左括号的后面去拼接一个 0char pre = showText.charAt(showText.length() - 1);if(pre == '(') {showText += "0";}// 这里也要去防止 (0+)这样的情况if(checkIsOp(pre)) {showText += "0"; // 去给它去补上 0}refreshText(showText + inputText);}}else  {// 点击了 数字 和 小数点// 这里要去监控 如果之前点击了小数点 这里的话 就不能再去进行拼接了if(inputText.equals(".")) {// 这里可能会出现很多的 小数点 例如: 0.000.if(!addPoint || getLastNumber(showText).contains(".")) { // 表示不可以去添加小数点refreshText(showText); // 保持原来的return ;} else {// 这里要去判断一下 小数点的前方是否为操作符 如果是的话 就自动拼接一个 0char pre = showText.charAt(showText.length() - 1);if(checkIsOp(pre) || checkIskh(pre)) {showText = showText + "0";}refreshText(showText + inputText); // 保持原来的addPoint = false;return;}}char pre = showText.charAt(showText.length() - 1);// 如果前面不是数字的话 要去自动补上加号if(pre == ')') {showText += "+";}refreshText(showText + inputText); // 拼接}}/*** 播放音乐的* @param inputText*/private void playSound(String inputText) {// 在这里Debug一下//  Toast.makeText(this, "点击了" + inputText, Toast.LENGTH_SHORT).show();playSoundMain(inputText, 0); // 默认都是单循环的}/*** 主要的声音播放方法* @param sound map里面的key* @param loop 表示循环的次数*/private void playSoundMain(String sound, int loop) {if (sp == null || hm.get(sound) == null) {Toast.makeText(this, "音频资源未加载或无效", Toast.LENGTH_SHORT).show();return;}// 获取AudioManager引用AudioManager am = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);// 获取当前音量float streamVolumeCurrent = am.getStreamVolume(AudioManager.STREAM_MUSIC);// 获取系统最大音量float streamVolumeMax = am.getStreamMaxVolume(AudioManager.STREAM_MUSIC);// 计算得到播放音量float volume = streamVolumeCurrent / (float) streamVolumeMax;// 调用SoundPool的play方法来播放声音文件currentId = sp.play(hm.get(sound), volume, volume, 1, loop, 1.0f);}/*** 计算的是 开根号 倒数 阶乘 π e* @param num 约定好的标志*            1:开根号*            2:倒数*            3:阶乘*            4:π*            5:绝对值*            6:e*            7:ln*/private void js3(int num) {String snum = getLastNumber(showText);String newNumber = "";if(num == 1) { // 开根号if(Double.parseDouble(snum) < 0) {abnormal(NAGATIVE_HAS_NO_SQRT);return;}newNumber = String.valueOf(Math.sqrt(Double.parseDouble(snum)));} else if(num == 2) { // 倒数的操作// 先去检查分母是不是为0的if(Double.parseDouble(snum) - 0.0 == 0) {abnormal(ISZERO); // 分母不可为 0return ;}addPoint = false; // 不能再去增加小数点了// 开始逻辑上的计算newNumber = String.valueOf(1.0 / Double.parseDouble(snum));} else if(num == 3) { // 阶乘// 注意:小数和分数没有阶乘 阶乘法只在自然数中进行if(!addPoint || showText.contains(".")) {// 表示当前是增加了小数的 是不能去进行阶乘的运算的abnormal(FACTORIALERROR);return; // 这个return 是为了防止 其他信息 的覆盖} else { // 表示当前是没有小数的 是可以进行阶乘的if(Integer.parseInt(snum) > 100) {abnormal(OVERFLOW); // 阶乘太大会导致溢出return ;} else if(Integer.parseInt(snum) < 0 ) {abnormal(NAGATIVE_HAS_NO_FACTORIAL); // 负数没有阶乘return;}newNumber = factorial(Integer.parseInt(snum));}} else if(num == 4) { //πaddPoint = false; // 注意 点击了PI 之后也要去限制小数点的newNumber = String.valueOf(Math.PI);} else if(num == 5) { // 绝对值的操作// 感觉这个绝对值 有点鸡肋if(Double.parseDouble(snum) < 0 ) {newNumber = snum.substring(1); // 把前面的符号给截取掉} else {// 但是这个新的 还要去规范一下 不能把前置 0 给显示newNumber = cancelZero(snum); // 不进行截取}} else if(num == 6) { // e 2.71828newNumber = String.valueOf(Math.E);} else if(num == 7) { // ln 的操作if(Double.parseDouble(snum) <= 0) {abnormal(LN_NEED_GREATER_THAN_ZERO);return ;}newNumber = String.valueOf(Math.log(Double.parseDouble(snum)));} else if(num == 8) { // log 的操作if(Double.parseDouble(snum) <= 0) {abnormal(LON_NEED_GREATER_THAN_ZERO);return ;}newNumber = String.valueOf(Math.log10(Double.parseDouble(snum)));}// 我需要找到最后这个的位置// over: 获得这个的num的位置 然后进行替换 把老的替换为新的// 我需要去找到 最后一个操作符的位置int pos = getLastOperatorPose(showText);// 开始进行替代 注意的是 这里的 substring 第二个参数表示的最后的位置 注意是 前闭后开的showText = showText.substring(0, pos + 1);char temp = showText.charAt(showText.length() - 1);// 如果最后一个不是运算符的话 就在去拼接一下加号 这个加号是默认的if(!checkIsOp(temp)) {showText += "+";}// 再去拼接新的showText = showText + newNumber;// 然后再去在界面进行显示出来refreshText(showText);}/*** 清空括号 也即是下面这种情况* 1: 按下C的时候* 2: 等号的时候*/private void clearKh() {leftParenthesis = 0;rightParenthesis = 0;// 清空之后要去刷新 数量refreshText(showText);}/*** 对结果进行规格化* @param text 传过来 需要规格化的数据*             例如: 00001 那么要返回的就是 1* @return*/private String cancelZero(String text) { // 取消前置无效0  以及后置无效0int j = 0;// 要对 test 进行校验一个// 有哪些情况呢?// 1: 00008// 2: 0000.1for(int i = 0; i < text.length() - 1; i ++ ) {if(text.charAt(i) == '0' && (!checkIsOp(text.charAt(i + 1)) && text.charAt(i + 1) != '.' || text.charAt(i + 1) == ')' || text.charAt(i + 1) == '(')) {j = i + 1;} else {break;}}text = text.substring(j); // 从这里开始截取 并包括当前这个return text;}/*** 获取 num 的 阶乘的* @param num 想要获取的 阶乘的 num* @return*/private String factorial(int num) {// 为了解决阶乘太大 用的是 BigIntegerBigInteger result = BigInteger.ONE; // 初始化为 1for (int i = 1; i <= num; i++) {result = result.multiply(BigInteger.valueOf(i)); // 逐步相乘}return String.valueOf(result); // 最后再去转换为 string类型的 给进行输出显示}/*** 根据text 抛出指定的异常*/private void abnormal(String show) {// 要去禁用按钮illegal(false);tv_result.setText(show);; // 并把错误的信息给显示到文本框里面}/*** 后退按钮的操作* @param t 出来的逻辑字符串* @return 返回的是 后退的字符串*/private String Backoff(String t) {for(int i = t.length() - 1; i >= 0; i -- ) {if(checkIsNum(t.charAt(i))) {// 需要注意的是 如果退的是 小数点的话 要求进行恢复if(t.charAt(i) == '.') {// 恢复 可以增加 小数点 的操作addPoint = true;}// 我就去后退一位return t.substring(0, i);} else {// 否则的话 就直接去回去的break;}}return t;}/*** 获得最后一个操作符的位置* @param showText 传来的字符串* @return 返回的是 最后一个操作符的位置* 例如: 1+2 返回的是1*/private int getLastOperatorPose(String showText) {int pos = -1;if(showText.charAt(0) == '-') {return pos;}for(int i = showText.length() - 1; i >= 0; i -- ) {if(checkIsOp(showText.charAt(i)) || checkIskh(showText.charAt(i))) { // 如果检查发现是 操作符的话 就去返回它的下标 是包括它的return i;}}// 这个表示的是没有操作符的return pos;}/*** 输出结果的规格化* @param js* @return 返回的是 规格化之后的结果*/private String Normalized(double js) {// 是可以去进行规格化的if(js - (int)(js) == 0) {return String.valueOf((int)(js));} else {return String.valueOf(js);}}/*** 清空 并进行 初始化* 新增 对 小数点 的恢复*/private void clear() {// 清空的时候 注意把 小数点的功能也给进行恢复addPoint = true;refreshOperate("");refreshText("0"); // 0即表示为不存在 其实也是存在}// 刷新运算结果private void refreshOperate(String new_result) {result = new_result;operator = "";}/** 刷新 文本 的操作* 再去加上 输出的校验* */private void refreshText(String text) {String khNum = "左括号的数量: " + leftParenthesis + " 右括号的数量: " + rightParenthesis;// 这里在刷新的时候 也要把 括号的数量给显示出来show_kh.setText(khNum);// 在刷新之前 对结果进行规格化一下 去除前置0的 那些没有效的数据 但是要对小数进行特判text = cancelZero(text);showText = text; // 默认一直在拼接if(denominatorIsZero) { // 分母是否为0showText = ISZERO;}tv_result.setText(showText);// 对 等号 按钮的监控if(leftParenthesis == rightParenthesis) {findViewById(R.id.btn_equal).setEnabled(true);} else {findViewById(R.id.btn_equal).setEnabled(false);}}/*** 主要的计算功能* @param s 传过来的 字符串 要去计算的字符串 这里面没有等号* @return*/private double js(String s) {// 第一个的 负数 是比较特殊的 要进行特判// 前面直接加上一个 0s = "0" + s;// 这里需要做一个判断// 可能是-3 这样的 但是返回的 也是-3 不要在进行计算下去了 这是一个独特的
//        if(s.charAt(0) == '-') {
//            s = "0" + s;
//        } else if(Objects.equals(operator, "")) {
//            return Double.parseDouble(s);
//        }// 用到java里面的桟的算法// 存取的是 数字Stack<Double> number = new Stack<>();// 存取的是 操作符Stack<Character> op = new Stack<>();String t = "";for(int i = 0; i < s.length(); i ++ ) {char temp = s.charAt(i);// 如果当前这个 temp 是 运算符的话if(checkIsOp(temp) || temp == '(' || temp == ')') { // 如果当前这个是 运算符// 这样的话 就需要把 字符串给转换为 Double// 注意 放进去的前提是不为空的 把他放到 桟里面if(!t.isEmpty()) {number.push(Double.valueOf(t));}t = "";// 然后 看看 当前的字符是什么类型的if(temp == '+' || temp == '-') {while(!op.isEmpty()) {// 拿到桟顶元素char operator = op.peek();if(operator == '(') { // 左括号的优先级是 最低 的break;}op.pop();// 然后再从 整数桟里面 去拿出来两个数 让其进行计算// TODO: 这两步数 是容易造成 error的 这点需要去着重的去关注double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();// 注意的是 后 操作 前 的double ret = js2(t2, t1, operator);number.push(ret);}// 到这里的时候 就表示 op里面是空的了op.push(temp);} else if(temp == 'x' || temp == '÷') {// 当时 乘法或者是 除法的时候 要去校验 它的下面是不是比它低的// 或者可以写成 前提是不为空 然后 op.peek() == 'x' || op.peek() == '➗'while(!op.isEmpty() && op.peek() != '+' && op.peek() != '-' && op.peek() != '(') {// 拿到桟顶元素char operator = op.peek();op.pop();// 然后再从 整数桟里面 去拿出来两个数 让其进行计算// TODO: 这两步数 是容易造成 error的 这点需要去着重的去关注double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();double ret = js2(t2, t1, temp);number.push(ret);}// 到这里的时候 是可以去当进去的op.push(temp);} else if(temp == ')') { // 这里对右括号单独进行限制// 只要还没遇到 左括号 就一直去把里面运算符的给弹出来 而且弹出来的时候 也把数字给弹出来两个 然后和这个弹出来的运算符进行计算while(!op.isEmpty()) {char operator = op.peek();op.pop();if(operator == '(') {break; // 就匹配成功了}// 否则的话 就取出来两个数字 然后把这个操作符 让这两个数进行运算的结果 放到存取数的桟里面// TODO: 但是这个的前提是存在的double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();double ret = js2(t2, t1, operator);number.push(ret);}} else if(temp == '(') { // 左括号的话 直接 push 进去op.push(temp);}} else if(checkIsNum(temp)){ // 说明是 数字 或者是小数点t = t + temp;}}// Debug 了半天才发现是这里出现了问题 我也是服了if(!t.isEmpty()) {// 注意在 类型转换的时候 看看是不是为空的 因为空的话 是不能去进行转换的number.push(Double.valueOf(t));}// 开始计算while (number.size() > 1) {// 这里 没有运算符 也是很致命的if(op.isEmpty()) {break;}double t1 = number.peek();number.pop();double t2 = number.peek();number.pop();number.push(js2(t2, t1, op.peek()));op.pop();}operator = "";return number.peek();}/*** 计算  + - * / 的* @param t1* @param t2* @param temp* @return*/private double js2(double t1, double t2, char temp) {if(temp == '+') {return t1 + t2;}if(temp == '-') {return t1 - t2;}if(temp == 'x') {return t1 * t2;}if(temp == '÷') {// 出现了 分母为0if(t2 == 0 ) {abnormal(ISZERO); // 分母不可为0 && 限制按钮的点击}return t1 / t2;}return 0.0; // 这个是假的}/*** 检查 是不是操作符* @param t* @return*/private Boolean checkIsOp(Character t) {return t == '+' || t == '-' || t == '÷' || t == 'x';}/*** 检查是不是 数字 这里把小数点也认为是数字了* @param t* @return*/private Boolean checkIsNum(Character t) {return (t >= '0' && t <= '9') || t == '.';}/*** 获得字符串 最后 一个 数字* @param s* @return*/private String getLastNumber(String s) {String ret = "";if(s.charAt(0) == '-') { // 表示的是负数ret = s;} else {for(int i = s.length() - 1; i >= 0; i -- ) {if(checkIsNum(s.charAt(i))) {ret = s.charAt(i) + ret;} else {break;}}ret = "0" + ret;}// 这个去解决的是 1233 + 也即是最后一个不是数字if(ret.contains(".")) { // 这个的目的是为了 防止 出现小数点之后 没有出现数字的情况 比如: 123.ret = ret + "0";}return ret;}/*** 去检查这个 t 是不是括号 因为要为括号进行特殊的操作* @param t* @return*/private boolean checkIskh(char t) {return t == '(' || t == ')';}// 封掉所有的按钮 单独剩下一个 清空的按钮 要去做出适当的提示// 表示的是 不合法 把全部的按钮全都给禁用了 除了 Cprivate void illegal(boolean value) {denominatorIsZero = !value;findViewById(R.id.btn_cancel).setEnabled(value);findViewById(R.id.btn_divide).setEnabled(value);findViewById(R.id.btn_multiply).setEnabled(value);findViewById(R.id.btn_clear).setEnabled(true); // 这个是特殊的findViewById(R.id.btn_seven).setEnabled(value);findViewById(R.id.btn_eight).setEnabled(value);findViewById(R.id.btn_nine).setEnabled(value);findViewById(R.id.btn_plus).setEnabled(value);findViewById(R.id.btn_four).setEnabled(value);findViewById(R.id.btn_five).setEnabled(value);findViewById(R.id.btn_six).setEnabled(value);findViewById(R.id.btn_minus).setEnabled(value);findViewById(R.id.btn_one).setEnabled(value);findViewById(R.id.btn_two).setEnabled(value);findViewById(R.id.btn_three).setEnabled(value);findViewById(R.id.btn_reciprocal).setEnabled(value);findViewById(R.id.btn_zero).setEnabled(value);findViewById(R.id.btn_dot).setEnabled(value);findViewById(R.id.btn_equal).setEnabled(value);findViewById(R.id.btn_sqrt).setEnabled(value);// 新增的 限制按钮findViewById(R.id.btn_PI).setEnabled(value);findViewById(R.id.btn_factorial).setEnabled(value);findViewById(R.id.btn_e).setEnabled(value);findViewById(R.id.btn_abs).setEnabled(value);// 新增的 限制按钮findViewById(R.id.btn_log).setEnabled(value);findViewById(R.id.btn_ln).setEnabled(value);findViewById(R.id.btn_left_kh).setEnabled(value);findViewById(R.id.btn_right_kh).setEnabled(value); // 对右括号 按钮进行监听}/*** 播放最后的运算结果* @param ret*/private void playRet(String ret) {// 先去播放一个等号playSound("=");// 这里是循环播放的答案for(int i = 0; i < ret.length(); i ++ ) {// 播放playSound(ret.charAt(i) + "");}}/*** 声音池的 初始化 init*/private void initSoundPool() {// 初始化声音池sp = new SoundPool.Builder().setMaxStreams(4).setAudioAttributes(new AudioAttributes.Builder().setContentType(AudioAttributes.CONTENT_TYPE_MUSIC).setUsage(AudioAttributes.USAGE_MEDIA).build()).build();hm = new HashMap<String, Integer>(); // 创建HashMap对象// 加载声音文件,并且设置为1号声音放入hm中// 数字的声音hm.put("1", sp.load(this, R.raw.one, 1));hm.put("2", sp.load(this,R.raw.two, 1));hm.put("3", sp.load(this,R.raw.three, 1));hm.put("4", sp.load(this,R.raw.four, 1));hm.put("5", sp.load(this,R.raw.five, 1));hm.put("6", sp.load(this,R.raw.six, 1));hm.put("7", sp.load(this,R.raw.seven, 1));hm.put("8", sp.load(this,R.raw.eight, 1));hm.put("9", sp.load(this,R.raw.nine, 1));hm.put("0", sp.load(this,R.raw.zero, 1));// 小数点的声音hm.put(".", sp.load(this,R.raw.point, 1));// 操作符的声音hm.put("=", sp.load(this,R.raw.equal, 1));hm.put("+", sp.load(this,R.raw.add, 1));hm.put("x", sp.load(this,R.raw.mut, 1));hm.put("÷", sp.load(this,R.raw.chu, 1));hm.put("-", sp.load(this,R.raw.jian, 1));hm.put("C", sp.load(this,R.raw.c, 1));hm.put("(", sp.load(this,R.raw.leftkh, 1));hm.put(")", sp.load(this,R.raw.rightkh, 1));// 运算操作hm.put("n!", sp.load(this,R.raw.jc, 1));hm.put("⌫", sp.load(this,R.raw.ht, 1));hm.put("π", sp.load(this,R.raw.pai, 1));hm.put("e", sp.load(this,R.raw.e, 1));hm.put("|x|", sp.load(this,R.raw.abs, 1));hm.put("1/x", sp.load(this,R.raw.ds, 1));hm.put("√", sp.load(this,R.raw.sqrt, 1));}
}

xml(界面)代码: 

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:background="#EEEEEE"android:padding="5dp"><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><!--显示简单 计算器 字样--><TextViewandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/simple_calculator"android:gravity="center"android:textColor="@color/black"android:textSize="20sp"/><TextViewandroid:id="@+id/show_kh"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="左括号数量为: 0  右括号数量为: 0"android:gravity="center"android:textColor="@color/black"android:textSize="20sp"/><!-- 计算机 文本的显示--><TextViewandroid:id="@+id/tv_result"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@color/white"android:text="0"android:textColor="@color/black"android:lines="3"android:gravity="right|bottom"android:textSize="25sp"/><GridLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:columnCount="4"android:rowCount="7"><!--后退一个--><Buttonandroid:id="@+id/btn_cancel"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/cancel"android:textColor="@color/black"/><!--除法--><Buttonandroid:id="@+id/btn_divide"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/divide"android:textColor="@color/black"/><!--乘法--><Buttonandroid:id="@+id/btn_multiply"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/multiply"android:textColor="@color/black"/><!--清零操作--><Buttonandroid:id="@+id/btn_clear"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/clear"android:textColor="@color/black"/><!--新增的操作--><Buttonandroid:id="@+id/btn_PI"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/PI"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_e"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/e"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_abs"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/abs"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_factorial"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/factorial"android:textColor="@color/black"/><!--这里又是新增加的 比如 左括号 右括号 --><Buttonandroid:id="@+id/btn_log"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/log"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_ln"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="ln"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_left_kh"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/left_kh"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_right_kh"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/right_kh"android:textColor="@color/black"/><!--下面是第二行--><Buttonandroid:id="@+id/btn_seven"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/seven"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_eight"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/eight"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_nine"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/nine"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_plus"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/plus"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_four"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/four"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_five"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/five"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_six"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/six"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_minus"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/minus"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_one"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/one"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_two"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/two"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_three"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/three"android:textColor="@color/black"/><!--这里显示的根号的图片--><Buttonandroid:id="@+id/btn_sqrt"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/sqrt"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_reciprocal"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/reciprocal"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_zero"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/zero"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_dot"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/dot"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_equal"android:layout_width="0dp"android:layout_height="@dimen/button_height"android:textSize="@dimen/button_font_size"android:layout_columnWeight="1"android:gravity="center"android:text="@string/equal"android:textColor="@color/black"/></GridLayout></LinearLayout></ScrollView></LinearLayout>

strings.xml里面的代码:

<resources><string name="app_name">黄淮计算器</string><string name="action_settings">Settings</string><!-- Strings used for fragments for navigation --><string name="first_fragment_label">First Fragment</string><string name="second_fragment_label">Second Fragment</string><string name="next">Next</string><string name="previous">Previous</string><string name="hello_word">hello_word</string><string name="text_for_color">textForColor</string><string name="lorem_ipsum"></string><string name="findyou">FindYou</string><string name="this_is_findyou">This is FindYou</string><string name="this_is_activity_main_2">除了奋斗 别无选择</string><!--计算器的定义--><string name="simple_calculator">黄淮计算器</string><string name="cancel">⌫</string><string name="divide">÷</string><string name="multiply">x</string><string name="clear">C</string><string name="seven">7</string><string name="eight">8</string><string name="nine">9</string><string name="plus">+</string><string name="four">4</string><string name="five">5</string><string name="six">6</string><string name="minus">-</string><string name="one">1</string><string name="two">2</string><string name="three">3</string><string name="reciprocal">1/x</string><string name="zero">0</string><string name="dot">.</string><string name="sqrt">√</string><string name="equal">=</string><string name="check_sex">请选择你的性别</string><string name="PI">π</string><string name="e">e</string><string name="abs">|x|</string><string name="factorial">n!</string><string name="log">log</string><string name="left_kh">(</string><string name="right_kh">)</string></resources>

如果这对你有帮助的话,记得start一下哦,你的star对我很重要!!!

gitee地址:

FindYou/移动开发


http://www.mrgr.cn/news/96802.html

相关文章:

  • 在Windows下使用Docker部署Nacos注册中心(基于MySQL容器)
  • 华为交换综合实验——VRRP、MSTP、Eth-trunk、NAT、DHCP等技术应用
  • MySQL数据库学习笔记1.SQL(1)
  • 使用 GitHub Pages 快速部署静态网页
  • Mysql之事务(下)
  • Linux安装Ubuntu24.04系统 并安装配置Nvidia 4090 显卡驱动
  • 论文阅读笔记:Denoising Diffusion Implicit Models (2)
  • STM32_HAL之程序编写、编译、烧写、上板测试初体验
  • 使用SpringBoot + Thymeleaf + iText实现动态PDF导出
  • git 按行切割 csv文件
  • echarts+HTML 绘制3d地图,加载散点+散点点击事件
  • C#:第一性原理拆解属性(property)
  • Anaconda和Pycharm的区别,以及如何选择两者
  • k8s 1.30 安装ingress-nginx
  • 为什么 Three.js 里 Cannon.js 物体堆叠时会有空隙?
  • 【C语言】深入理解指针(三):C语言中的高级指针应用
  • Prompt攻击是什么
  • Anolis系统下安装Jenkins
  • 检查是否存在占用内存过大的SQL
  • Unity中 粒子系统使用整理(一)