Android简易计算器实现
实验目的:
自主完成一个简单APP的设计工作,综合应用已经学到的Android UI设计技巧,重点注意合理使用布局。
实验要求:
1. 完成一个计算器的设计,可以以手机自带的计算器为参考。设计过程中,注意考虑界面的美观性,不同机型的适应性,以及功能的完备性。
2. 注意结合Activity的生命周期,考虑不同情况下计算器的界面状态。
3. 如有余力,可以考虑实现一个高精度科学计算型的计算器。
代码实现
(1)MainActivity.java文件
package com.example.administrator.lianghui; import java.util.Arrays; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; public class MainActivity extends AppCompatActivity implements View.OnClickListener{ Button btn_0; Button btn_1; Button btn_2; Button btn_3; Button btn_4; Button btn_5; Button btn_6; Button btn_7; Button btn_8; Button btn_9; Button btn_point; //小数点 Button btn_clear; //清除 Button btn_del; //删除 Button btn_plus; Button btn_minus; Button btn_multiply; Button btn_divide; Button btn_equal; Button btn_left; Button btn_right; private TextView et_input; private StringBuilder pending = new StringBuilder(); private void initView() { btn_0 = (Button) findViewById(R.id.btn_0); btn_1 = (Button) findViewById(R.id.btn_1); btn_2 = (Button) findViewById(R.id.btn_2); btn_3 = (Button) findViewById(R.id.btn_3); btn_4 = (Button) findViewById(R.id.btn_4); btn_5 = (Button) findViewById(R.id.btn_5); btn_6 = (Button) findViewById(R.id.btn_6); btn_7 = (Button) findViewById(R.id.btn_7); btn_8 = (Button) findViewById(R.id.btn_8); btn_9 = (Button) findViewById(R.id.btn_9); btn_point = (Button) findViewById(R.id.btn_point); btn_clear = (Button) findViewById(R.id.btn_clear); btn_del = (Button) findViewById(R.id.btn_del); btn_plus = (Button) findViewById(R.id.btn_plus); btn_minus = (Button) findViewById(R.id.btn_minus); btn_multiply = (Button) findViewById(R.id.btn_multiply); btn_divide = (Button) findViewById(R.id.btn_divide); btn_equal = (Button) findViewById(R.id.btn_equal); et_input = (TextView) findViewById(R.id.et_input); btn_left = (Button) findViewById(R.id.btn_left); btn_right = (Button) findViewById(R.id.btn_right); btn_0.setOnClickListener(this); btn_1.setOnClickListener(this); btn_2.setOnClickListener(this); btn_3.setOnClickListener(this); btn_4.setOnClickListener(this); btn_5.setOnClickListener(this); btn_6.setOnClickListener(this); btn_7.setOnClickListener(this); btn_8.setOnClickListener(this); btn_9.setOnClickListener(this); btn_point.setOnClickListener(this); btn_plus.setOnClickListener(this); btn_equal.setOnClickListener(this); btn_minus.setOnClickListener(this); btn_multiply.setOnClickListener(this); btn_del.setOnClickListener(this); btn_divide.setOnClickListener(this); btn_clear.setOnClickListener(this); btn_divide.setOnClickListener(this); btn_left.setOnClickListener(this); btn_right.setOnClickListener(this); et_input.setKeyListener(null); } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } @Override public void onClick(View v) { int last = 0; if(pending.length()!=0) { last = pending.codePointAt(pending.length()-1); } switch (v.getId()) { case R.id.btn_0: pending = pending.append("0"); et_input.setText(pending); break; case R.id.btn_1: pending = pending.append("1"); et_input.setText(pending); break; case R.id.btn_2: pending = pending.append("2"); et_input.setText(pending); break; case R.id.btn_3: pending = pending.append("3"); et_input.setText(pending); break; case R.id.btn_4: pending = pending.append("4"); et_input.setText(pending); break; case R.id.btn_5: pending = pending.append("5"); et_input.setText(pending); break; case R.id.btn_6: pending = pending.append("6"); et_input.setText(pending); break; case R.id.btn_7: pending = pending.append("7"); et_input.setText(pending); break; case R.id.btn_8: pending = pending.append("8"); et_input.setText(pending); break; case R.id.btn_9: pending = pending.append("9"); et_input.setText(pending); break; case R.id.btn_plus: if (last >= '0' && last <= '9' ) { pending = pending.append("+"); } et_input.setText(pending); break; case R.id.btn_minus: if (last >= '0' && last <= '9') { pending = pending.append("-"); } et_input.setText(pending); break; case R.id.btn_multiply: if (last >= '0' && last <= '9' ) { pending = pending.append("*"); } et_input.setText(pending); break; case R.id.btn_divide: if (last >= '0' && last <= '9' ) { pending = pending.append("/"); } et_input.setText(pending); break; case R.id.btn_point: if (judje1()) { pending = pending.append("."); et_input.setText(pending); } break; case R.id.btn_right: if((last>='0' &&last<='9'||last==')')&&judje2()==1) { pending = pending.append(")"); et_input.setText(pending); } break; case R.id.btn_left: if((last!='(')||(last<='0' &&last>='9')){ pending = pending.append("("); et_input.setText(pending); } break; case R.id.btn_del: //删除 if (pending.length() != 0) { pending = pending.delete(pending.length() - 1, pending.length()); et_input.setText(pending); } break; case R.id.btn_clear: //清空 pending = pending.delete(0, pending.length()); et_input.setText(pending); break; case R.id.btn_equal: // =等于 if ((pending.length() > 1)) { InfixInToDuffix inf = new InfixInToDuffix(); String jieguo; try { String a = inf.toSuffix(pending); jieguo = inf.dealEquation(a); } catch (Exception ex) { jieguo = "出错"; } et_input.setText(pending + "=" + jieguo); pending = pending.delete(0, pending.length()); if (Character.isDigit(jieguo.charAt(0))) { pending = pending.append(jieguo); } } break; default: break; } } private boolean judje1() { String a = "+-*/."; int[] b = new int[a.length()]; int max; for (int i = 0; i < a.length(); i++) { String c = "" + a.charAt(i); b[i] = pending.lastIndexOf(c); } Arrays.sort(b); if (b[a.length() - 1] == -1) { max = 0; } else { max = b[a.length() - 1]; } if (pending.indexOf(".", max) == -1) { return true; } else { return false; } } private int judje2(){ int a=0,b=0; for(int i = 0 ; i < pending.length() ;i++){ if(pending.charAt(i)=='(' ) { a++; } if(pending.charAt(i)==')' ) { b++; } } if(a == b) return 0; if(a > b) return 1; return 2; } }
(2)布局文件 activity_main.xml文件
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="2"> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/et_input" android:textSize="40sp" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:orientation="horizontal" android:weightSum="4"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="C" android:textSize="40sp" android:id="@+id/btn_clear" android:background="#FFC0CB" android:layout_weight="1"/> <Button android:id="@+id/btn_divide" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#FFC0CB" android:text="/" android:textSize="40sp"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="*" android:textSize="40sp" android:id="@+id/btn_multiply" android:layout_weight="1" android:background="#FFC0CB"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="B" android:textSize="40sp" android:id="@+id/btn_del" android:layout_weight="1" android:background="#FFC0CB"/> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:layout_weight="1" android:gravity="center" android:weightSum="4"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="7" android:textSize="30sp" android:id="@+id/btn_7" android:layout_weight="1" android:background="#ffffcc"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="8" android:textSize="30sp" android:id="@+id/btn_8" android:layout_weight="1" android:background="#ffffcc"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="9" android:textSize="30sp" android:id="@+id/btn_9" android:layout_weight="1" android:background="#ffffcc"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="-" android:textSize="50sp" android:id="@+id/btn_minus" android:layout_weight="1" android:background="#44ffff"/> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="1" android:weightSum="4"> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="4" android:textSize="30sp" android:id="@+id/btn_4" android:layout_weight="1" android:background="#ffffcc"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="5" android:textSize="30sp" android:id="@+id/btn_5" android:layout_weight="1" android:background="#ffffcc"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="6" android:textSize="30sp" android:id="@+id/btn_6" android:layout_weight="1" android:background="#ffffcc"/> <Button android:id="@+id/btn_plus" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="#44ffff" android:text="+" android:textSize="40sp" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="1" android:weightSum="4" > <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="1" android:textSize="30sp" android:id="@+id/btn_1" android:layout_weight="1" android:background="#FFFFCC"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="2" android:textSize="30sp" android:id="@+id/btn_2" android:layout_weight="1" android:background="#FFFFCC"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="3" android:textSize="30sp" android:id="@+id/btn_3" android:layout_weight="1" android:background="#FFFFCC"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="." android:textSize="40sp" android:id="@+id/btn_point" android:layout_weight="1" android:background="#44ffff"/> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_weight="1" android:weightSum="4" > <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="(" android:textSize="30sp" android:id="@+id/btn_left" android:layout_weight="1" android:background="#FFFFCC"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="0" android:textSize="30sp" android:id="@+id/btn_0" android:background="#FFFFCC" android:layout_weight="1" /> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text=")" android:textSize="30sp" android:id="@+id/btn_right" android:layout_weight="1" android:background="#FFFFCC"/> <Button android:layout_width="0dp" android:layout_height="match_parent" android:text="=" android:textSize="30sp" android:id="@+id/btn_equal" android:background="#99CCFF" android:layout_weight="1"/> </LinearLayout> </LinearLayout>
(3)还有实现运算逻辑过程的文件 InfixInToDuffix.java文件
package com.example.administrator.lianghui; import java.util.HashMap; import java.util.List; import java.util.Map; import java.lang.*; import java.util.ArrayList; import java.util.*; public class InfixInToDuffix { private static final Map<Character,Integer>basic =new HashMap<Character, Integer>(); static { basic.put('-',1); basic.put('+', 1); basic.put('*', 2); basic.put('/', 2); basic.put('(', 0); } //将中缀表达式转换为后缀表达式 public String toSuffix(StringBuilder infix){ List<String> queue = new ArrayList<String>(); List<Character> stack = new ArrayList<Character>(); char[] charArr = infix.substring(0,infix.length()).trim().toCharArray(); String standard = "*/+-()"; char ch = '&'; int len = 0; for (int i = 0; i < charArr.length; i++) { ch = charArr[i]; if(Character.isDigit(ch)) { len++; }else if(ch == '.'){ len++; }else if(standard.indexOf(ch) != -1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i))); len = 0; } if(ch == '(') { stack.add(ch); continue; } if (!stack.isEmpty()) { int size = stack.size() - 1; boolean flag = false; while (size >= 0 && ch == ')' && stack.get(size) != '(') { queue.add(String.valueOf(stack.remove(size))); size--; flag = true; } if(ch==')'&&stack.get(size) == '('){ flag = true; } while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) { queue.add(String.valueOf(stack.remove(size))); size--; } } if(ch != ')') { stack.add(ch); } else { stack.remove(stack.size() - 1); } } if(i == charArr.length - 1) { if(len > 0) { queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len+1, i+1))); } int size = stack.size() - 1; while (size >= 0) { queue.add(String.valueOf(stack.remove(size))); size--; } } } String a = queue.toString(); return a.substring(1,a.length()-1); } public String dealEquation(String equation){ String [] arr = equation.split(", "); List<String> list = new ArrayList<String>(); for (int i = 0; i < arr.length; i++) { int size = list.size(); switch (arr[i]) { case "+": double a = Double.parseDouble(list.remove(size-2))+ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(a)); break; case "-": double b = Double.parseDouble(list.remove(size-2))- Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(b)); break; case "*": double c = Double.parseDouble(list.remove(size-2))* Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(c)); break; case "/": double d = Double.parseDouble(list.remove(size-2))/ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(d)); break; default: list.add(arr[i]); break; } } return list.size() == 1 ? list.get(0) : "运算失败" ; } }
在美化页面布局的过程中,已经运行通过的程序又出现了bug,con’t resolve symbol R.原因是对布局按钮进行标记时写入了程序无法识别的符号“<”。改过之后,程序就可以正常运行了。
实现逻辑运算的InfixInToDuffix.java文件是将中缀表达式转换为后缀表达式。由于APP运行时是按中缀的方式输入,但是中缀计算结果难度比后缀大很多,所以先将中缀转换为后缀,再进行计算。
中缀表达式转后缀表达式规则:
1)如果遇到操作数,我们就直接将其输出。
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
4)如果遇到任何其他的操作符,如(“+”, “*”,“(”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) "的情况下我们才弹出" ( ",其他情况我们都不会弹出" ( "。
5)如果读到了输入的末尾,则将栈中所有元素依次弹出。