Android Studio计算器功能
小和同学 人气:0代码:
activity_3.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent" android:layout_height="match_parent" tools:context=".Activity3"> <RelativeLayout android:id="@+id/r1" android:layout_width="match_parent" android:layout_height="100dp" android:background="#1000" tools:ignore="MissingConstraints"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/text1" android:layout_margin="6dp" android:textSize="24sp" android:text=""> </TextView> <TextView android:id="@+id/textv" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentRight="true" android:text="0" android:padding="20dp" android:textSize="30sp"/> </RelativeLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_marginTop="100dp" > <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="22dp" android:onClick="onClick" android:text="%" android:backgroundTint="#A67D3D" android:textColor="#171616"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="22dp" android:onClick="onClicka" android:text="CE" android:backgroundTint="#A67D3D" android:textColor="#171616" tools:ignore="OnClick" /> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="22dp" android:onClick="onClick" android:textAllCaps="false" android:text="Back" android:backgroundTint="#A67D3D" android:textColor="#171616"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#E91E63" android:backgroundTint="#8E2323" android:onClick="onClick" android:text="÷" android:textSize="24dp" app:backgroundTint="#2196F3" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="1" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="2" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="3" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:backgroundTint="#8E2323" android:onClick="onClick" android:text="×" android:textSize="24dp" app:backgroundTint="#9C27B0" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="4" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="5" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="6" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="-" android:backgroundTint="#8E2323"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="7" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="8" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="9" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="+" android:backgroundTint="#8E2323"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:textSize="24dp" android:onClick="onClick" android:text="0" android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textSize="24dp" android:onClick="onClick" android:text="." android:backgroundTint="#0000FF"/> <Button android:layout_width="0dp" android:textSize="30dp" android:layout_height="match_parent" android:layout_weight="1" android:onClick="onClick" android:text="=" android:backgroundTint="#8E2323"/> </LinearLayout> </LinearLayout> </RelativeLayout> </androidx.constraintlayout.widget.ConstraintLayout>
Activity3.java
package com.example.myapplication; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; import java.math.BigDecimal; import java.util.Stack; import java.util.ArrayList; import java.util.Iterator; import java.util.regex.Pattern; public class Activity3 extends AppCompatActivity { Stack<String> operator; //用于求解后缀表达式和计算 String memorry = "0"; //计算器M(R C + -)操作 int flag = 1; //判断是否要完全修改显示的值 boolean clearstr = false; //是否清除表达式的标志位 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_3); operator = new Stack<>(); } //此方法用于计算,操作数分别为a和b,运算符为opr protected String operation(String a, String b, String opr){ String result = null; //存放运算结果 BigDecimal ope1 = new BigDecimal(a); //为了有较好的精度,选择BigDecimal对象进行计算 BigDecimal ope2 = new BigDecimal(b); switch (opr){ case "+": result = ope1.add(ope2).stripTrailingZeros().toPlainString(); break; //stripTrailingZeros每一种运算都把小数点后多余的0去除 case "-": result = ope1.subtract(ope2).stripTrailingZeros().toPlainString(); break; //toPlainString不用科学计数法显示 case "×": result = ope1.multiply(ope2).stripTrailingZeros().toPlainString(); break; case "÷": try{ result = ope1.divide(ope2, 8, BigDecimal.ROUND_HALF_UP).stripTrailingZeros().toPlainString(); //保留8位小数,捕获异常 }catch (Exception e){ result = "错误"; } break; case "^": result = String.valueOf(Math.pow(Double.parseDouble(a), Double.parseDouble(b))); break; //计算X的Y次方 case "`": result = String.valueOf(Math.pow(Double.parseDouble(a), (1 / Double.parseDouble(b)))) ; break; //计算X的1/Y次方 } if(result.equals("NaN") || result.equals("Infinity")) result = "错误"; //虽然java中无穷大和负数的开根号并不会出现错误,但为了方便操作,显示提醒用户错误 return replaces(result); //replaces方法去除多余的0 } //方法重载 //由于BigDecimal对象并没有提供以下函数,所以重载方法,采用double类型计算,但会丢失精度 protected String operation(String a, String str){ double result = 1; switch (str){ case "sin": result = Math.sin(Double.parseDouble(a)); break; case "cos": result = Math.cos(Double.parseDouble(a)); break; case "tan": result = Math.tan(Double.parseDouble(a)); break; case "n!": if(!a.contains(".")) for(int i = 2; i <= Integer.parseInt(a); i++){ result *= i; } break; } return replaces(String.valueOf(result)); //replaces方法去除多余的0 } //去掉多余的0 protected String replaces(String s){ if(s != null && s.indexOf(".") > 0){ s = s.replaceAll("0+?$", "");//去掉多余的0 s = s.replaceAll("[.]$", "");//如最后一位是.则去掉 } return s; } //Java没有提供栈的清空函数,需要自己定义 protected void clearStack(Stack<String> operator){ while(!operator.isEmpty()){ operator.pop(); } } //求两个运算符的优先级的相对大小 protected int priority(String a, String b) { int x = 0, y = 0; switch(a) { case "(": case ")": x = 3; break; case "^": case "`": x = 2; break; case "×": case "÷": x = 1; break; case "+": case "-": x = 0; break; } switch(b) { case "(": case ")": y = 3; break; case "^": case "`": y = 2; break; case "×": case "÷": y = 1; break; case "+": case "-": y = 0; break; } return x - y; } //求后缀表达式 protected String bolan(ArrayList<String> array) { StringBuffer stb = new StringBuffer(); //存放后缀表达式,需要频繁修改字符串,使用StringBuffer Iterator<String> it = array.iterator(); //迭代器 Pattern pattern = Pattern.compile("[0-9]+.*[0-9]*"); //匹配非运算符的正则表达式 String op = null; //临时存放array数组内容 while(it.hasNext()) { //遍历数组 op = it.next().toString(); /* 求后缀表达式过程: 1 如果是数字,直接加入后缀表达式 2 如果是运算符: a.若为'(',入栈; b.若为')',依次把栈中的运算符加入后缀表达式,知道出现'(',并把'('出栈; c.若为'+' '-' '*' '/': 1)栈空,入栈; 2)栈顶元素为'(',入栈; 3)高于栈顶元素优先级,入栈; 4)否则,依次弹出栈顶运算符,直到一个优先级比它低的运算符或'('为止 d.遍历完成,若栈非空依次弹出所有元素 */ switch(op) { case "(": operator.push(op); break; case ")": while(!operator.peek().equals("(")) { stb.append(operator.pop() + " ");//pop()移除一个元素并将该元素返回 } operator.pop(); break; case "+": case "-": case "×": case "÷": case "^": case "`": if(operator.isEmpty() || operator.peek().equals("(") || priority(op, operator.peek())>0) { operator.push(op); }else { while(!operator.isEmpty() && priority(op, operator.peek()) <= 0 && !operator.peek().equals("(")) { stb.append(operator.pop() + " "); } if(!operator.isEmpty() && operator.peek().equals("(")) operator.pop(); operator.push(op); } break; } if(pattern.matcher(op).matches()) { stb.append(op + " "); } } while(!operator.isEmpty()) { stb.append(operator.pop() + " "); } return stb.toString(); } //判断字符是运算符还是数字的函数 protected boolean isOperator(char c) { boolean flag = false; switch(c) { case '+': case '-': case '×': case '÷': case '(': case ')': case '^': case '`':flag = true; break; } return flag; } //把字符串切分到数组中 protected ArrayList<String> Split(String str) { ArrayList<String> list = new ArrayList<>(); StringBuffer sbf = new StringBuffer(); if(str.charAt(0) == '-') str = '0' + str; //如果字符以负号开始,则在字符串头加入0 for(int i = 0; i < str.length(); i++) { //遍历所有字符 if(isOperator(str.charAt(i))) { if(sbf.length()>0) list.add(sbf.toString()); //如果当前字符是运算符,把sbf的内容作为整体作为List的一项 sbf.delete(0, sbf.length()); //清空sbf的内容 list.add(String.valueOf(str.charAt(i))); }else { sbf.append(str.charAt(i)); //如果当前的字符不是运算符,就加入到sbf中,到下一个运算符出现为止,可以保证多位数的数字不被分割 } } if(sbf.length() > 0) list.add(sbf.toString()); //此时的sbf保存了最后一个操作数,应该加入List数组 return list; } //所有Button的绑定函数 public void onClick(View view){ Button btn = (Button) view; //接收到的参数转换为Button对象 TextView tv = (TextView) this.findViewById(R.id.textv); //获取TextView组件 TextView tv1 = (TextView) this.findViewById(R.id.text1); String str = btn.getText().toString(); //获取按钮的文本以确定按下的是哪个按钮 String text = tv.getText().toString(); //获取显示框的文本 if(clearstr){ clearstr = false; //此位为真,需要把输入的表达式清空 tv1.setText(""); } String totalstr = tv1.getText().toString(); //获取显示在左上角的表达式字符串 String result = null, a, b; if(text.equals("错误")){ //出现除0错误后,无论点击哪个按钮都只做显示文本0的操作 clearStack(operator); //所有的点击操作都使计算器重置 tv.setText("0"); flag = 1; return; } if(str.equals("x^y")){ //计算器按钮上的文本是多位字符,修改为一位方便操作 str = "^"; }else if(str.equals("x^1/y")){ //计算器按钮上的文本是多位字符,修改为一位方便操作 str = "`"; } switch (str){ case "0": case "1": case "2": case "3": case "4": case "5": case "6": case "7": case "8": case "9": if(flag == 1){ //flag为1,说明当前还没输入或上一次运算已经结束,不需要再保存当前显示的数字 result = str; if(str.equals("0")){ flag = 1; //如果点击0,则flag保持不变,防止当前显示0的情况下点击0会出现多个0的情况 }else{ flag = 0; //如果点击的不是0,flag改为0 } }else if(flag == 0){ //flag为0时,当前点击的数字直接加到文本显示的数字之后 result = text + str; } break; case "+": case "×": case "÷": case "^": case "`": if(flag == 1){ //连续多次点击符号按钮,仅保留最后一次点击的符号 if(totalstr.length() > 0 && !totalstr.endsWith("(")){ //把上一次点击的符号去除后添加当前符号 int temp = totalstr.length(); totalstr = totalstr.substring(0, temp - 1) + str; } }else if(!totalstr.endsWith(")")){ //以)结尾,点击运算符后直接加入到表达式后面 totalstr = totalstr + text + str; }else totalstr = totalstr + str; //点击了数字后又点了运算符,需要把数字和运算符都加入到表达式 tv1.setText(totalstr); flag = 1; break; case "-": if(totalstr.endsWith("(") && flag == 1){ //负数的输入需要在负号前加上0,方便操作的统一 totalstr = totalstr + "0" + str; }else{ if(flag == 1){ if(totalstr.length() > 0){ // 重复点击了运算符,把上一次点击的符号去除后添加当前符号 int temp = totalstr.length(); totalstr = totalstr.substring(0, temp - 1) + str; }else{ //负数的输入需要在负号前加上0,方便操作的统一 totalstr = "0" + str; } }else if(!totalstr.endsWith(")")){ //输入完了右括号,点击负号直接加入表达式,否则把当前输入的数字和负号一起加入表达式 totalstr = totalstr + text + str; }else totalstr = totalstr + str; } tv1.setText(totalstr); flag = 1; break; case "=": //点击等号后把表达式转化成后缀表达式,并求值 clearStack(operator); //求值之前先清空栈,防止出现错误 if(!totalstr.endsWith(")")){ //如果不是以右括号结尾,说明当前输入的数并没有加入到表达式中,需要加入后再进行操作 totalstr = totalstr + text; tv1.setText(totalstr); } try{ //运算过程中出现任何错误都在显示框中显示“错误” for(String z:bolan(Split(totalstr)).split(" ")) { //z为后缀表达式的每一项 /* 计算过程: 遇到运算符,则从栈中弹出两个数进行运算,并把结果入栈; 遇到数字,入栈 */ if(isOperator(z.charAt(0))) { b = operator.pop(); a = operator.pop(); result = replaces(operation(a, b, z)); //出栈两个数进行运算 operator.push(result); //运算结果入栈 }else { operator.push(z); //数字直接入栈 } } }catch (Exception e){ tv.setText("错误"); } flag = 1; //点击等号后下次点击其他按钮需要清空表达式 clearstr = true; break; case "(": if(totalstr.length() > 0 && !Character.isDigit(totalstr.charAt(totalstr.length() - 1))){ //表达式非空且以运算符结尾直接加入 totalstr = totalstr + str; }else if(totalstr.length() == 0) totalstr = str; //如果表达式为空,直接加入 tv1.setText(totalstr); break; case ")": totalstr = totalstr + text + str; //把当前数字加上右括号加入到表达式 tv1.setText(totalstr); break; case "CE": tv.setText("0"); //请零当前输入的数字 flag = 1; break; case "C": tv1.setText(""); //重置 tv.setText("0"); flag = 1; break; case ".": if(flag == 1){ //flag为1时,按下数字需要更改文本框显示按下的数字,按下小数点则显示0加小数点 result = "0."; flag = 0; }else if(!text.contains(".")){ //当前显示数字已经含有小数点,不进行任何操作,否则加上小数点 result = text + str; } break; case "Back": if(text.length() == 1 || flag == 1){ //如果只有1位或运算完成了,点击Back直接显示0 result = "0"; flag = 1; }else{ int lenth = text.length(); result = text.substring(0, lenth - 1); //截取前n-1个字符 } break; case "√X": result = String.format("%f", Math.sqrt(Double.parseDouble(text))); //计算x平方根 if(result.equals("NaN")) result = "错误"; flag = 1; result = replaces(result); //清除多余的0 break; case "x²": result = String.format("%f",Math.pow(Double.parseDouble(text), 2)); //计算x平方 result = replaces(result); //清除多余的0 flag = 1; break; case "1/x": result = String.format("%f", 1 / Double.parseDouble(text)); if(result.equals("Infinity")) result = "错误"; //当出现1/0时结果为Infinity(无穷大),让计算器显示错误 flag = 1; result = replaces(result); break; case "%": result = operation(text, "100", "÷"); flag = 1; break; case "MR": tv.setText(memorry); //显示内存里存储的数 flag = 1; break; case "MC": memorry = "0"; //内存清零 flag = 1; break; case "M+": memorry = operation(memorry, text, "+"); //内从中的数加上当前显示的数 break; case "M-": memorry = operation(memorry, text, "-"); //内从中的数减去当前显示的数 break; case "sin": case "cos": case "tan": case "n!": result = operation(text, str); flag = 1; break; } if(result != null) tv.setText(result); } }
结果:
加载全部内容