在学习了Android第一行代码的前三章后开始了自己的第一个android小项目,由于接触android时间不长,再加上个人审美能力较差,因此界面做的不是很好,大致可以体现出来一个计算器的界面。。。实现简单的计算器并不难,只要掌握了活动,布局以及控件的基本使用就可以开发出一个简单的android版计算器了
我外层用的是外层相对布局,然后内层有四个线性布局加一个TextView控件,由于刚开始学,理解还不是特别深,因此布局这块写的可能感觉有点乱。。因为内层的线性布局采用了垂直布局,所以才写成了这样。。其实可以整体采用百分比布局或者外层垂直线性布局,内层水平线性布局,这样会比较清楚一点,以下是我的布局代码
<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;
}
}