Android小项目——简单计算器的实现

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<String> value = new ArrayDeque<>();
        //该集合用来存储运算符
        ArrayDeque<String> 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;
    }
}

猜你喜欢

转载自blog.csdn.net/yjh728/article/details/81565336
今日推荐