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;    }}

更多相关文章

  1. 运行时报错:Invoke-customs are only supported starting with An
  2. 【android工程转为lib工程后提示'R.id.xxx不能作为case语句的表
  3. Android(安卓)getResources的作用和需要注意点
  4. Android--取出SDcard卡上指定后缀名的文件
  5. Android(安卓)支持的 media 文件格式--MediaFile
  6. Android(安卓)Studio 使用 Lambda表达式
  7. android 正则表达式
  8. Android(安卓)getResources的作用和需要注意点
  9. Mac版Android(安卓)studio中使用lambda表达式设置jdk版本问题

随机推荐

  1. android 关于使用androidStudio开发串口
  2. Android(安卓)中的 adapter
  3. Android十岁了,它是如何逆袭成全球最多人
  4. 为android开放类增加自定义成员方法[转]
  5. Android(安卓)UI 之 TabLayout动态添加ta
  6. Android嵌入式启动篇
  7. 转战Android
  8. 【移动开发】Android应用程序完全退出
  9. 第十篇ANDROID的ActionBar及菜单机制
  10. 恩布900手机客服,安卓版本号Entboost Andr