Android实现小米手机自带的计算器

最近突发兴趣,想自己实现一个提供四则混合运算的计算器,心动不如行动,就开始用Android来具体的实现下。但这种小Demo听着简单,实现起来还是需要一些参考。考虑到界面的美观性,我最终选择了小米手机自带的计算器来模仿。

这个计算器的图大概是这样的

小米计算器

以前学习栈的时候,我们知道,要实现一个能进行简单混合运算的计算器功能,需要通过两个栈将中缀表达式转换为前缀表达式(或后缀表达式),而且逻辑也比较复杂。如果对这个有兴趣的可以看我另一篇博客,里面有详细的程序流程图:https://blog.csdn.net/c_o_d_e_/article/details/108774118

在这里我就不讲上述的方法了。我仔细研究过小米计算器,发现它设计的也比较巧妙,每次输入数字都会进行运算一次,这样就不必将运算表达式转换为前/后缀表达式再去操作,省了不少麻烦。我最开始用过两种办法去模仿,都以失败告终(看来悟性不好、算法熟练度太低,人比较笨呀),后面就把前面乱七八糟写在一块的代码全部删除,然后从新开始设计算法。深思熟虑后,发现其实这个计算器的没有那么难。只是我没有想到点子上去。我的思路是:单独写一个工具类,用于处理并计算字符串,并从左到右依次计算然后返回结果。在Acticity的后台代码中就只需要每次输入数字时,就将当前的整个字符串传递给工具类,然后获取值即可。

思路清晰后,写代码就比较轻松,下面是我的工具类代码和部分核心Activity代码,界面布局由于不精通,这里就不弄上来了,后面可以去我的github仓库下载

计算器类Calculator

import java.util.regex.Pattern;

/**
 * 实现计算功能的封装类
 * 这里的计算只需要考虑从左到右依次计算,且不需考虑括号
 */
public class Calculator {
    public static final String PRE = "(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)";//数字及小数校验正则表达式
    public static final String PRE_SYMBOL = "[\\+\\-\\×\\÷\\%]";//运算符匹配表达式
    /**
     * 传入表达式,计算并返回结果
     * @param expre 传入的表达式
     * @return 计算结果
     */
    public static String calculation(String expre){
        //分别获取数字和运算符的数组集合
        String[] sSymbol = Pattern.compile(PRE).matcher(expre).replaceAll("").split("");
        String[] sNum = expre.split(PRE_SYMBOL);

        String result = sNum[0];
        for (int i = 1; i < sNum.length; i++) {
            //这里注意在模拟器上,split后的长度不一定就是0,symbols在split后的长度问题,还没搞懂原因
            result = calc(result,sNum[i],sSymbol[i-1]);
        }
        return result;
    }

    //计算两个数的结果
    public static String calc(String a,String b,String symbol){
        double result = 0;
        switch (symbol){
            case "+":
                result = Double.parseDouble(a) + Double.parseDouble(b);break;
            case "-":
                result = Double.parseDouble(a) - Double.parseDouble(b);break;
            case "×":
                result = Double.parseDouble(a) * Double.parseDouble(b);break;
            case "÷":
                result = Double.parseDouble(a) / Double.parseDouble(b);break;
            case "%":
                if(b.equals("") || b == "")//只有一个数就除以100
                    result = Double.parseDouble(a) / 100;
                else//两个数就取模运算
                    result = Double.parseDouble(a) % Double.parseDouble(b);
                break;
            default:
                throw new RuntimeException("参数不合法:"+"a="+a+",b="+b+",symbol="+symbol);
        }
        //如果resutl结果是整数,就去掉.0后缀
        return (Math.round(result)-result==0) ? String.valueOf((long)result) : String.valueOf(result);
    }
}

Activity类的部分关键代码,主要是提供一种思路

import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.TextView;
import java.util.regex.Pattern;


public class MainActivity extends AppCompatActivity implements View.OnClickListener {
 
    //输入的文本内容
    private static StringBuilder InputTextContent = new StringBuilder("0");
    //显示结果的文本内容
    private static StringBuilder resultTextContent = new StringBuilder("=");

    //输入内容的文本对象,下面统称为【输入文本框】
    TextView inputText;
    //计算结果的文本对象,下面统称为【计算结果文本框】
    TextView resultText;

    public static final String PRE = "(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)";//数字校验正则表达式
    public static final String PRE_SYMBOL = "[\\+\\-\\×\\÷\\%]";//运算符匹配表达式

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        inputText  = (TextView)findViewById(R.id.input_text);
        resultText = (TextView)findViewById(R.id.result_text);

       
        bingButton();//绑定按钮点击事件

    }

    /**
     * 按钮及监听事件的绑定
     * 共19个按钮
     */
    private void bingButton(){
        Button button1 = (Button)findViewById(R.id.button1);
        button1.setOnClickListener(this);//绑定事件
        ImageButton button2 = (ImageButton)findViewById(R.id.button2);
        button2.setOnClickListener(this);
        Button button3 = (Button)findViewById(R.id.button3);
        button3.setOnClickListener(this);
        Button button4 = (Button)findViewById(R.id.button4);
        button4.setOnClickListener(this);
        Button button5 = (Button)findViewById(R.id.button5);
        button5.setOnClickListener(this);
        Button button6 = (Button)findViewById(R.id.button6);
        button6.setOnClickListener(this);
        Button button7 = (Button)findViewById(R.id.button7);
        button7.setOnClickListener(this);
        Button button8 = (Button)findViewById(R.id.button8);
        button8.setOnClickListener(this);
        Button button9 = (Button)findViewById(R.id.button9);
        button9.setOnClickListener(this);
        Button button10 = (Button)findViewById(R.id.button10);
        button10.setOnClickListener(this);
        Button button11 = (Button)findViewById(R.id.button11);
        button11.setOnClickListener(this);
        Button button12 = (Button)findViewById(R.id.button12);
        button12.setOnClickListener(this);
        Button button13 = (Button)findViewById(R.id.button13);
        button13.setOnClickListener(this);
        Button button14 = (Button)findViewById(R.id.button14);
        button14.setOnClickListener(this);
        Button button15 = (Button)findViewById(R.id.button15);
        button15.setOnClickListener(this);
        Button button16 = (Button)findViewById(R.id.button16);
        button16.setOnClickListener(this);
        Button button17 = (Button)findViewById(R.id.button17);
        button17.setOnClickListener(this);
        Button button18 = (Button)findViewById(R.id.button18);
        button18.setOnClickListener(this);
        Button button19 = (Button)findViewById(R.id.button19);
        button19.setOnClickListener(this);
    }


    //实现OnClickListener接口的onClick方法,自定义实现其点击事件
    @Override
    public void onClick(View view) {
        switch (view.getResources().getResourceEntryName(view.getId())){
            case "button1" : // C
                OptionC();
                break;
            case "button2" : // 回退
                back();
                break;
            case "button3" : // ÷
                addAndCalc("÷");
                break;
            case "button4" : // ×
                addAndCalc("×");
                break;
            case "button5" :// 7
                addAndCalc("7");
                break;
            case "button6" :// 8
                addAndCalc("8");
                break;
            case "button7" :// 9
                addAndCalc("9");
                break;
            case "button8" :// -
                addAndCalc("-");
                break;
            case "button9" :// 4
                addAndCalc("4");
                break;
            case "button10" :// 5
                addAndCalc("5");
                break;
            case "button11" :// 6
                addAndCalc("6");
                break;
            case "button12" :// +
                addAndCalc("+");
                break;
            case "button13" :// 1
                addAndCalc("1");
                break;
            case "button14" :// 2
                addAndCalc("2");
                break;
            case "button15" :// 3
                addAndCalc("3");
                break;
            case "button16" :// %
                addAndCalc("%");
                break;
            case "button17" :// 0
                addAndCalc("0");
                break;
            case "button18" :// .
                addAndCalc(".");
                break;
            case "button19" :// =
                // 传入表达式,计算结果,赋给结果文本框对象显示
                clickEqual();
                break;
            default:
                break;
        }

        //添加字符时,要将【输入文本框】字体变大
        inputText.setTextSize(60);
        inputText.setText(InputTextContent);

    }


    /**
     * 各操作方法的具体实现
     */

    //C 清除
    public void OptionC(){
        InputTextContent = new StringBuilder("0");//清空结果,恢复为初始的0
        resultText.setVisibility(View.INVISIBLE);//隐藏计算结果文本框
    }

    //回退 清除一个数
    public void back(){
        if(InputTextContent.length()>1){//不止一个字符
            InputTextContent.delete(InputTextContent.length()-1,InputTextContent.length());
            //获取当前输入的字符前面一个字符
            String lastElement = InputTextContent.substring(InputTextContent.length()-1,InputTextContent.length());
            //暂未完成
        }
        else{
            InputTextContent = new StringBuilder("0");//删除完后归零
            resultText.setVisibility(View.INVISIBLE);//隐藏计算结果文本框
        }


    }

    //点击等号
    public void clickEqual(){
        if(isCorrect(InputTextContent.toString())){//表达式能够计算就进行计算并显示结果
            resultText.setText("="+Calculator.calculation(InputTextContent.toString()));//设置内容
            resultText.setVisibility(View.VISIBLE);//设为可见
            resultText.setTextSize(60);//设置大小
        }
    }


    //每次添加一个元素到字符串,就对该字符串进行计算
    public void addAndCalc(String newNext){
        //获取当前输入的字符前面一个字符
        String lastElement = InputTextContent.substring(InputTextContent.length()-1,InputTextContent.length());
        if(
            Pattern.compile(PRE_SYMBOL).matcher(newNext).find()//输入的是符号
            &&
            (
                InputTextContent.length() == 1 && InputTextContent.toString().equals("0")//是第一次输入
                ||
                Pattern.compile(PRE_SYMBOL).matcher(lastElement).find()//输入前的最后一个元素也是符号
            )
        ){
            //Nothing...
        }else{
            if(InputTextContent.length() == 1 && InputTextContent.toString().equals("0")){
                //当只有一个数字且为0时,这个0就要被清除掉,从而解决刚开始输入去除0的问题
                InputTextContent = new StringBuilder("");
            }
            //将新的数字添加到尾部
            InputTextContent.append(newNext);

            //将输入的数据显示到【输入文本框】
            inputText.setText(InputTextContent);

            //字符串符合计算表达式规则就进行运算
            if(isCorrect(InputTextContent.toString())){
                //将该字符串计算出来,并显示到【计算结果文本框】
                resultText.setText("="+Calculator.calculation(InputTextContent.toString()));
                resultText.setVisibility(View.VISIBLE);
            }
        }
    }

    //验证表达式是否能够进行计算
    public boolean isCorrect(String expre){
        String[] symbols = {};
        String[] nums = expre.split(PRE_SYMBOL);
        if(Pattern.compile(PRE_SYMBOL).matcher(expre).find())//字符串中有符号就进行拆分{
        {
            symbols = Pattern.compile(PRE).matcher(expre).replaceAll("").split("");
        }

        //判断规则就是“符号数组比数字数字少1”
        if(symbols.length < nums.length)//模拟器上symbols在split后的长度问题,还没搞懂原因
            return true;
        return false;
    }

   
}

晚上很晚才弄完,代码没时间优化(主要是懒,不想弄了,哈哈),不过思路还是比较简单的。

猜你喜欢

转载自blog.csdn.net/c_o_d_e_/article/details/109541918