Android小项目——简单计算器的实现
16lz
2021-01-23
Android实现简单计算器
前言
在学习了Android第一行代码的前三章后开始了自己的第一个android小项目,由于接触android时间不长,再加上个人审美能力较差,因此界面做的不是很好,大致可以体现出来一个计算器的界面。。。实现简单的计算器并不难,只要掌握了活动,布局以及控件的基本使用就可以开发出一个简单的android版计算器了
界面部分
我外层用的是外层相对布局,然后内层有四个线性布局加一个TextView控件,由于刚开始学,理解还不是特别深,因此布局这块写的可能感觉有点乱。。因为内层的线性布局采用了垂直布局,所以才写成了这样。。其实可以整体采用百分比布局或者外层垂直线性布局,内层水平线性布局,这样会比较清楚一点,以下是我的布局代码
<?xml version="1.0" encoding="utf-8"?><RelativeLayout 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=".MainActivity"> <LinearLayout android:id="@+id/jiemian" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true"> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/first" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:orientation="vertical"> <Button android:id="@+id/symbol_ac" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="AC" android:textColor="#007dfe" android:textSize="24sp" /> <Button android:id="@+id/number_7" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="7" android:textSize="24sp" /> <Button android:id="@+id/number_4" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="4" android:textSize="24sp" /> <Button android:id="@+id/number_1" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="1" android:textSize="24sp" /> <Button android:id="@+id/symbol_left" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="(" android:textSize="24sp" /> LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/second" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:orientation="vertical"> <Button android:id="@+id/symbol_div" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="/" android:textColor="#007dfe" android:textSize="24sp" /> <Button android:id="@+id/number_8" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="8" android:textSize="24sp" /> <Button android:id="@+id/number_5" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="5" android:textSize="24sp" /> <Button android:id="@+id/number_2" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="2" android:textSize="24sp" /> <Button android:id="@+id/number_0" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="0" android:textSize="24sp" /> LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/third" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:orientation="vertical"> <Button android:id="@+id/symbol_mult" android:layout_width="match_parent" android:layout_height="85dp" android:background="#f5f5f5" android:text="×" android:textColor="#007dfe" android:textSize="30sp" /> <Button android:id="@+id/number_9" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="9" android:textSize="24sp" /> <Button android:id="@+id/number_6" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="6" android:textSize="24sp" /> <Button android:id="@+id/number_3" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text="3" android:textSize="24sp" /> <Button android:id="@+id/symbol_right" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="@android:color/white" android:text=")" android:textSize="24sp" /> LinearLayout> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/end" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layout_weight="1" android:orientation="vertical"> <Button android:id="@+id/symbol_del" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="←" android:textColor="#007dfe" android:textSize="30sp" /> <Button android:id="@+id/symbol_sub" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="-" android:textColor="#007dfe" android:textSize="24sp" /> <Button android:id="@+id/symbol_add" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="+" android:textColor="#007dfe" android:textSize="24sp" /> <Button android:id="@+id/symbol_dian" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="1" android:background="#f5f5f5" android:text="." android:textColor="#007dfe" android:textSize="24sp" /> <Button android:id="@+id/symbol_equal" android:layout_width="match_parent" android:layout_height="85dp" android:layout_weight="2" android:background="#007dfe" android:text="=" android:textColor="@android:color/white" android:textSize="24sp" /> LinearLayout> LinearLayout> <TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentStart="true" android:layout_alignParentTop="true" android:layout_marginTop="90dp" android:maxLines="1" android:textSize="24sp" />RelativeLayout>
逻辑部分
在计算方面采用了中缀表达式转后缀表达式,然后后缀表达式计算得出结果。参考以下两篇文章:
将中缀表达式转化为后缀表达式
后缀表达式的计算
代码如下
package com.example.yjh.test;import java.math.BigDecimal;import java.util.ArrayDeque;public class Calculator { //计算表达式的值 public String caculate(String string) throws Exception { //该部分用来验证中缀表达式是否合理 //若右括号数量大于左括号,则说明表达式不合理,抛出异常 //否则说明正常,继续进行运算 int x = 0; for (int i = 0; i < string.length(); i++) { if (string.charAt(i) == '(') { x++; } else if (string.charAt(i) == ')') { x--; } } if (x < 0) { throw new Exception("错误,右括号数量大于左括号"); } //该集合用来存储操作数 ArrayDeque value = new ArrayDeque<>(); //该集合用来存储运算符 ArrayDeque operation = new ArrayDeque<>(); //该字符串用来临时存储转化后的后缀表达式 StringBuilder stringBuilder = new StringBuilder(); //将中缀表达式的操作数和运算符分离并存放到字符串数组中 String[] expression = formatInput(string); //遍历字符串数组 for (String s : expression) { //若该字符串为空则跳过 if (s.equals(" ") || s.length() == 0) { continue; } else if (s.charAt(0) == '-' && !s.equals("-")) { //若为是负数,则添加至后缀表达式末尾,并补上空格,方便后面将后缀表达式分离 stringBuilder.append(s + " "); } else if (isDigital(s.charAt(0))) { //若为正数,添加至后缀表达式并补空格 stringBuilder.append(s + " "); } else if (isOperater(s.charAt(0)) || s.charAt(0) == '(' || s.charAt(0) == ')') { //若为运算符,继续判断 if (s.equals("(")) {//若为左括号,则压入运算符栈中 operation.push(s); continue; } //若为右括号,则将运算符栈中第一个左括号以上全部弹出并添加至后缀表达式,左括号直接弹出,不用添加至后缀表达式 if (s.equals(")")) { while (!operation.getFirst().equals("(")) { if (!operation.getFirst().equals("(")) { stringBuilder.append(operation.poll()+" "); } } if (operation.getFirst().equals("(")) { operation.pop(); continue; } } //若运算符栈为空,则将运算符压入栈中 if (operation.isEmpty()) { operation.push(s); continue; } else if (priorityIsBiggerOrTheSame(s, operation.getFirst())) { //若该运算符比栈顶运算符优先级高,则压入栈中 operation.push(s); continue; } else { //否则弹出所有优先级不比它低的运算符并添加至后缀表达式 while (!operation.isEmpty() && !priorityIsBiggerOrTheSame(s, operation.getFirst())) { stringBuilder.append(operation.poll() +" "); } operation.push(s); continue; } } } //弹出操作数栈中所有元素并添加至后缀表达式 while (!operation.isEmpty()) { stringBuilder.append(operation.poll()); } //格式化后缀表达式(将操作数与运算符分离) expression = formatInfixExpression(stringBuilder.toString()); //清空后缀表达式 stringBuilder.delete(0, stringBuilder.length()); //遍历字符串数组 for (String s : expression) { //若该字符串为空,则跳过 if (s.equals(" ") || s.length() == 0) { continue; } else if (isDigital(s.charAt(0))) { //若为正数则压入操作数栈中 value.push(s); } else if (s.charAt(0) == '-' && !s.equals("-")) { //若为负数,则压入操作数栈中 value.push(s); } else if (isOperater(s.charAt(0))) { //若为运算符,则判断操作数个数大于2个,则进行弹出两个操作数进行操作,然后将结果压入操作数栈中 if (value.size() >= 2) { BigDecimal last = new BigDecimal(value.poll()); BigDecimal last_p = new BigDecimal(value.poll()); if (s.equals("-")) { value.push(last_p.subtract(last).toString()); } else if (s.equals("+")) { value.push(last_p.add(last).toString()); } else if (s.equals("*")) { value.push(last_p.multiply(last).toString()); } else if (s.equals("/")) { value.push(last_p.divide(last, 15, BigDecimal.ROUND_HALF_DOWN).toString()); } } } } //弹出最终运算结果并返回 return value.poll(); } //判断是否为运算符,若为运算符,则返回true,否则返回false public static boolean isOperater(int a) { if (a == '+' || a == '-' || a == '*' || a == '/') return true; return false; } //判断是否为数字,若为数字,则返回true,否则返回false public static boolean isDigital(int a) { if (a >= '0' && a <= '9') return true; return false; } // 格式化中缀表达式输入,即在符号前后添加空格,便于后面的分隔操作 public static String[] formatInput(String s) { String temp = ""; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (i == 0 && c == '-') { temp += c; } else if (isOperater(c) || c == '(' || c == ')') { if ((i - 1) >= 0 && (i + 1) < s.length() && (isOperater(s.charAt(i - 1)) || s.charAt(i - 1) == '(' || s.charAt(i - 1) == ' ') && c == '-' && isDigital(s.charAt(i + 1))) { temp += " " + c; } else { temp += " " + c + " "; } } else temp += c;// 数字不用加空格 } return temp.split(" ");// 分割 } //格式化后缀表达式 public static String[] formatInfixExpression(String s) { String temp = ""; for (int i = 0; i < s.length(); i++) { char c = s.charAt(i); if (isOperater(c)) { if (c == '-' && i + 1 < s.length() && isDigital(s.charAt(i + 1))) { temp += " " + c; } else { temp += " " + c + " "; } } else { temp += c;// 数字不用加空格 } } return temp.split(" ");// 分割 } // 优先级判断,a是否大于b public static boolean priorityIsBiggerOrTheSame(String a, String b) { String s = " +- */"; return s.indexOf(a) - s.indexOf(b) >= 2; }}
在主活动部分获取了按钮的实例,然后为按钮创建点击事件,并在用户输入时做了一些限制。部分限制如下(还有一些限制没有列出来,在代码中体现):
- 一个操作数不能有两个小数点
- 左括号不能和运算符直接相连,符号除外
- 当数字和右括号相连时,自动在数字和右括号之间补上乘号
代码如下:
import android.os.Bundle;import android.support.v7.app.AppCompatActivity;import android.text.method.ScrollingMovementMethod;import android.view.View;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;import java.util.ArrayList;import java.util.List;public class MainActivity extends AppCompatActivity implements View.OnClickListener { private TextView textView; public StringBuilder results = new StringBuilder(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Button button0 = (Button) findViewById(R.id.number_0); Button button1 = (Button) findViewById(R.id.number_1); Button button2 = (Button) findViewById(R.id.number_2); Button button3 = (Button) findViewById(R.id.number_3); Button button4 = (Button) findViewById(R.id.number_4); Button button5 = (Button) findViewById(R.id.number_5); Button button6 = (Button) findViewById(R.id.number_6); Button button7 = (Button) findViewById(R.id.number_7); Button button8 = (Button) findViewById(R.id.number_8); Button button9 = (Button) findViewById(R.id.number_9); Button button_add = (Button) findViewById(R.id.symbol_add); Button button_sub = (Button) findViewById(R.id.symbol_sub); Button button_mult = (Button) findViewById(R.id.symbol_mult); Button button_div = (Button) findViewById(R.id.symbol_div); Button button_del = (Button) findViewById(R.id.symbol_del); Button button_dian = (Button) findViewById(R.id.symbol_dian); Button button_equal = (Button) findViewById(R.id.symbol_equal); Button button_left = (Button) findViewById(R.id.symbol_left); Button button_right = (Button) findViewById(R.id.symbol_right); Button button_ac = (Button) findViewById(R.id.symbol_ac); this.textView = (TextView) findViewById(R.id.text_view); textView.setMovementMethod(ScrollingMovementMethod.getInstance()); button0.setOnClickListener(this); button1.setOnClickListener(this); button2.setOnClickListener(this); button3.setOnClickListener(this); button4.setOnClickListener(this); button5.setOnClickListener(this); button6.setOnClickListener(this); button7.setOnClickListener(this); button8.setOnClickListener(this); button9.setOnClickListener(this); button_add.setOnClickListener(this); button_sub.setOnClickListener(this); button_mult.setOnClickListener(this); button_div.setOnClickListener(this); button_del.setOnClickListener(this); button_dian.setOnClickListener(this); button_left.setOnClickListener(this); button_ac.setOnClickListener(this); button_right.setOnClickListener(this); button_equal.setOnClickListener(this); } @Override public void onClick(View view) { int last = 0; int last_p = 0; if (results.length() != 0) { last = results.codePointAt(results.length() - 1); if (results.length() > 1) last_p = results.codePointBefore(results.length() - 1); } if (results.indexOf("=") > 0) { results.replace(0, results.length(), ""); } switch (view.getId()) { case R.id.number_0: if (last == ')') { results.append("*0"); } else { results.append('0'); } textView.setText(results); break; case R.id.number_1: if (last == ')') { results.append("*1"); } else { results.append('1'); } textView.setText(results); break; case R.id.number_2: if (last == ')') { results.append("*2"); } else { results.append('2'); } textView.setText(results); break; case R.id.number_3: if (last == ')') { results.append("*3"); } else { results.append('3'); } textView.setText(results); break; case R.id.number_4: if (last == ')') { results.append("*4"); } else { results.append('4'); } textView.setText(results); break; case R.id.number_5: if (last == ')') { results.append("*5"); } else { results.append('5'); } textView.setText(results); break; case R.id.number_6: if (last == ')') { results.append("*6"); } else { results.append('6'); } textView.setText(results); break; case R.id.number_7: if (last == ')') { results.append("*7"); } else { results.append('7'); } textView.setText(results); break; case R.id.number_8: if (last == ')') { results.append("*8"); } else { results.append('8'); } textView.setText(results); break; case R.id.number_9: if (last == ')') { results.append(" * 9"); } else { results.append('9'); } textView.setText(results); break; case R.id.symbol_add: if (isDigital(last) || last == ')' || last == '.') { results.append('+'); } else if (isOperater(last) && isOperater(last_p)) { results.replace(results.length() - 2, results.length(), "+"); } else if (isOperater(last)) { results.setCharAt(results.length() - 1, '+'); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_sub: if (isDigital(last) || last == ')' || last == '(' || last == '.') { results.append('-'); } else if (last == '-' || last == '+') { results.setCharAt(results.length() - 1, '-'); } else if (last == '*' || last == '/') { results.append('-'); } else if (results.length() == 0) { results.append('-'); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_mult: if (isDigital(last) || last == ')' || last == '.') { results.append('*'); } else if (isOperater(last)) { results.setCharAt(results.length() - 1, '*'); } else if (isOperater(last) && isOperater(last_p)) { results.replace(results.length() - 2, results.length(), "*"); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_div: if (isDigital(last) || last == ')' || last == '.') { results.append('/'); } else if (isOperater(last) && isOperater(last_p)) { results.replace(results.length() - 2, results.length(), "/"); } else if (isOperater(last)) { results.setCharAt(results.length() - 1, '/'); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_del: if (results.indexOf("=") > 0) { results.replace(0, results.length(), ""); } else if (results.length() > 0) { results.deleteCharAt(results.length() - 1); } textView.setText(results); break; case R.id.symbol_ac: results.delete(0, results.length()); textView.setText(results); break; case R.id.symbol_dian: int index = results.lastIndexOf("."); boolean flag = false; for (int i = index; i > 0 && i < results.length(); i++) { int x = results.charAt(i); if (isOperater(x) || x == '(' || x==')') { flag = true; break; } } if ((isDigital(last) && flag) || (isDigital(last) && index<0)) { results.append('.'); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_left: if (last == '-' && isOperater(last_p)) { results.replace(results.length() - 1, results.length(), "(-"); } else if (isDigital(last)) { results.append("*("); } else if (isOperater(last)) { results.append('('); } else if (last == ')') { results.append("*("); } else if (last == '(') { results.append('('); } else if (results.length() == 0) { results.append('('); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_right: if (isDigital(last) || last == ')') { results.append(')'); } else { Toast.makeText(MainActivity.this, "错误", Toast.LENGTH_SHORT).show(); } textView.setText(results); break; case R.id.symbol_equal: try { Calculator calculator = new Calculator(); results.replace(0, results.length(), calculator.caculate(results.toString())); textView.setText(results); } catch (Exception e) { textView.setText(e.getMessage()); results.replace(0, results.length(), ""); } default: break; } } public static boolean isOperater(int a) { if (a == '+' || a == '-' || a == '*' || a == '/') return true; return false; } public static boolean isDigital(int a) { if (a >= '0' && a <= '9') return true; return false; }}
更多相关文章
- 【android工程转为lib工程后提示'R.id.xxx不能作为case语句的表
- Android--取出SDcard卡上指定后缀名的文件
- Android Studio 使用 Lambda表达式
- android 正则表达式
- Mac版Android studio中使用lambda表达式设置jdk版本问题
- Android 正则表达式验证手机和邮箱格式是否正确
- Android Studio中快速替换styles的正则表达式
- lambda表达式进行对象结合操作的实例详解
- C#中匿名委托以及Lambda表达式的实例详解