Android小项目--Suzy计算器

一.前提准备

  1. 在Android Studio下新建一个项目并全部选择默认
  2. 对Android界面和布局有一定了解;对Android活动有一些了解
  3. 对Java基础知识有一些了解
  4. 掌握中缀表达式转后缀表达式,以及对后缀表达式求值算法

二.实现效果

  1.  
  2. 整数和浮点数的加减乘除运算
  3. 可以加括号
  4. 可以实现大数的计算
  5. 部分截图

               

     

三.界面编写

  1. 我使用的是百分比布局,因此在app/build.gradle的dependencies中添加一条语句
    implementation 'com.android.support:percent:28.0.0-beta01'
                                               //版本号

    并点击Sync Now

  2. 界面编写:添加计算器所需的Button以及输入时所需的TextView,,修改Activity_main.xml代码如下:

    
        <Button
            android:id=
            android:layout_above=
            android:layout_toLeftOf=
            android:background=
            android:text=
            android:textColor=
            android:layout_marginRight=
            android:layout_marginBottom=
            android:textSize=
            app:layout_heightPercent=
            app:layout_widthPercent="/>
    <Button
            .../>
        ...
    
        <TextView
            android:id=
            android:layout_width=
            android:layout_height=
            android:layout_alignParentStart=
            android:layout_alignParentTop=
            android:layout_marginTop=
            android:textSize= />

     

  3. 可以设置圆角:在app/src/main/res/drawable下添加shape.xml文件,并添加如下内容
     

    <?xml version="1.0" encoding="utf-8" ?>
    <!--相当于做了一张圆角的图片,然后给button作为背景图片-->
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <!--设置背景色-->
        <solid android:color="#f8f8ff" />
        <!--设置圆角-->
        <corners android:radius="20dip" />
        <!--<padding-->
        <!--android:bottom="10dp"-->
        <!--android:left="10dp"-->
        <!--android:right="10dp"-->
        <!--android:top="10dp"-->
        <!--/>-->
        <!--设置边框线的宽度和颜色-->
        <stroke android:width="2dp" android:color="#ffebcd" />
    </shape>

     在Button中的background中选择此

    android:background="@drawable/shape"

     

  4. 修改名字和app图标:
    修改名字:修改app/src/main/values/Strings.xml如下:

    <resources>
        <string name="app_name">Suzy计算器</string>
    </resources>
    

     修改app图标:先将图片保存在app/src/main/mipmap文件中,再修改AndroidManifest.xml文件

    
        <application
            android:allowBackup=
            android:icon="@mipmap/tubiao"//这一句
            android:label=

     

四.活动编写

  1. 为得到正确的中缀表达式,要限制输入:
    字符过多会显示不完整,因此要限制字符个数;
    同一个小数只能有一个小数点;
    “+-*/”不能同时出现两个及以上;
    左括号前不能时数字,右括号后不能是数字;
    左括号数量大于右括号数量才能输入右括号;
    制输入"."表示0.
  2. 未实现:除0;不能直接输入负数
  3. 为每个Button设置点击事件,修改MainActivity中的代码:
    public class MainActivity extends AppCompatActivity implements View.OnClickListener{
        private StringBuilder s = new StringBuilder();
        private TextView textView;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Button button1 = (Button)findViewById(R.id.button1);
            Button button2 = (Button)findViewById(R.id.button2);
            Button button3 = (Button)findViewById(R.id.button3);
            Button button4 = (Button)findViewById(R.id.button4);
            Button button5 = (Button)findViewById(R.id.button5);
            Button button6 = (Button)findViewById(R.id.button6);
            Button button7 = (Button)findViewById(R.id.button7);
            Button button8 = (Button)findViewById(R.id.button8);
            Button button9 = (Button)findViewById(R.id.button9);
            Button button10 = (Button)findViewById(R.id.button10);
            Button button11 = (Button)findViewById(R.id.button11);
            Button button12 = (Button)findViewById(R.id.button12);
            Button button13 = (Button)findViewById(R.id.button13);
            Button button14 = (Button)findViewById(R.id.button14);
            Button button15 = (Button)findViewById(R.id.button15);
            Button button16 = (Button)findViewById(R.id.button16);
            Button button17 = (Button)findViewById(R.id.button17);
            Button button18 = (Button)findViewById(R.id.button18);
            Button button19 = (Button)findViewById(R.id.button19);
            Button button20 = (Button)findViewById(R.id.button20);
            textView=(TextView)findViewById(R.id.output);
    
            //注册监听器(接口实现)
            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);
            button10.setOnClickListener(this);
            button11.setOnClickListener(this);
            button12.setOnClickListener(this);
            button13.setOnClickListener(this);
            button14.setOnClickListener(this);
            button15.setOnClickListener(this);
            button16.setOnClickListener(this);
            button17.setOnClickListener(this);
            button18.setOnClickListener(this);
            button19.setOnClickListener(this);
            button20.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                //数字前边不能是右括号
                case R.id.button16:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0){
                        textView.setText("0");
                    } else {
                        s.append("0");
                        textView.setText(s.toString());
                    }
                    break;
                case R.id.button17:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("1");
                    textView.setText(s.toString());
                    break;
                case R.id.button12 :
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("2");
                    textView.setText(s);
                    break;
                case R.id.button7:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("3");
                    textView.setText(s.toString());
                    break;
                case R.id.button18:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("4");
                    textView.setText(s.toString());
                    break;
                case R.id.button13:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("5");
                    textView.setText(s.toString());
                    break;
                case R.id.button8:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("6");
                    textView.setText(s.toString());
                    break;
                case R.id.button19:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("7");
                    textView.setText(s.toString());
                    break;
                case R.id.button14:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("8");
                    textView.setText(s.toString());
                    break;
                case R.id.button9:
                    if(isRightBracket())
                        break;
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    s.append("9");
                    textView.setText(s.toString());
                    break;
                case R.id.button5://加
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0)//以“+”开头时不显示
                        break;
                    String ss = s.substring(s.length()-1,s.length());
                    if(ss.equals("("))
                        break;
                    if(Replace(ss)){
                        s.delete(s.length()-1,s.length());
                    }
                    s.append("+");
                    textView.setText(s.toString());
                    break;
                case R.id.button4://减
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0)//以“-”开头时不显示
                        break;
                    String ss1 = s.substring(s.length()-1,s.length());
                    if(ss1.equals("("))
                       break;
                    if(Replace(ss1)){
                        s.delete(s.length()-1,s.length());
                    }
                    s.append("-");
                    textView.setText(s.toString());
                    break;
                case R.id.button3://乘
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0)//以“*”开头时不显示
                        break;
                    String ss2 = s.substring(s.length()-1);
                    if(ss2.equals("("))
                        break;
                    if(Replace(ss2)){
                        s.delete(s.length()-1,s.length());
                    }
                    s.append("*");
                    textView.setText(s.toString());
                    break;
                case R.id.button2://除
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0)//以“/”开头时不显示
                        break;
                    String ss3 = s.substring(s.length()-1,s.length());
                    if(ss3.equals("("))
                        break;
                    if(Replace(ss3)){
                        s.delete(s.length()-1,s.length());
                    }
                    s.append("/");
                    textView.setText(s.toString());
                    break;
                case R.id.button11://小数点
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0){//以小数点开头表示0.几
                        s.append("0.");
                        textView.setText(s.toString());
                        break;
                    }
                    String ss4 = s.substring(s.length()-1,s.length());
                    if(ss4.equals('('))
                        break;
                    if(ss4.equals(')'))
                        break;
                    if(hasPoint()){
                        break;
                    }
                    if(Replace(ss4)){
                        s.delete(s.length()-1,s.length()-0);
                    }
                    s.append(".");
                    textView.setText(s.toString());
                    break;
                case R.id.button20://左括号
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0){
                        s.append("(");
                        textView.setText(s.toString());
                        break;
                    }
                    String ss5 = s.substring(s.length()-1,s.length());
                    if(AddLeftBracket(ss5)){
                        s.append("(");
                        textView.setText(s.toString());
                    }
                    break;
                case R.id.button15://右括号
                    if(!isEnough()){
                        Toast.makeText(this,"长度超限",
                                Toast.LENGTH_SHORT).show();
                        break;
                    }
                    if(s.length()==0)
                        break;
                    if(AddRightBracket() && WithLeft()){
                        s.append(")");
                        textView.setText(s.toString());
                    }
                    break;
                case R.id.button10://删除
                    if(s.length()>=1){
                        s.delete(s.length()-1,s.length()-0);
                        textView.setText(s.toString());
                    }
                    break;
                case R.id.button6://清0
                    s.replace(0,s.length(),"");
                    textView.setText(s.toString());
                    break;
                case R.id.button1://等于号
                    MoreLeftBracket(s);//判断是否需要补全右括号
                    String end = InfixToPostfix.dealEquation(InfixToPostfix.toSuffix(s));
                    s.delete(0,s.length());
                    s.append(end);
                    textView.setText(end);
                    break;
                default:
                    break;
            }
        }
    
        //输入时需要的函数
        private boolean isRightBracket(){//判断前边是不是“)”
            char[] c = s.toString().toCharArray();
            if(c.length==0)
                return false;
            if(c[c.length-1]==')')
                return true;
            return false;
        }
        private boolean isEnough(){//判断长度是否超限
            boolean b = true;
            if(s.length()==89)
                b=false;
            return b;
        }
        private boolean Replace(String ss){
            boolean b = false;
            if(ss.equals("+")) b=true;
            if(ss.equals("-")) b=true;
            if(ss.equals("*")) b=true;
            if(ss.equals("/")) b=true;
            if(ss.equals(".")) b=true;
            if(ss.equals("(")) b=true;
            return b;
        }
    
        private boolean hasPoint(){//判断是否已经有小数点(注意判断的是同一个数中有没有两个小数点)
            boolean b = false;
            char[] c = s.toString().toCharArray();
            //倒着看,第一个不是数字的符号如果是 小数点 就不满足需求
            int i;
            for(i = c.length-1;i>=0 && c[i]>='0' && c[i]<='9';i-- ){}
            if(i!=-1){
                if(c[i]=='.')
                    b=true;
            }
            return b;
        }
        private boolean AddLeftBracket(String ss){
            boolean b = false;
            if(ss.equals("+"))
                b=true;
            if(ss.equals("-"))
                b=true;
            if(ss.equals("*"))
                b=true;
            if(ss.equals("/"))
                b=true;
            if(ss.equals("("))
                b=true;
            return b;
        }
        private boolean AddRightBracket(){
            boolean b = true;
            String ss = s.substring(s.length()-1,s.length());
            if(ss.equals("+"))
                b=false;
            if(ss.equals("-"))
                b=false;
            if(ss.equals("*"))
                b=false;
            if(ss.equals("/"))
                b=false;
            if(ss.equals("."))
                b=false;
            if(ss.equals("("))
                b=false;
            return b;
        }
        private boolean WithLeft(){
            boolean b = true;
            char[] ch = s.toString().toCharArray();
            int x=0,y=0;
            for(int i = 0;i<ch.length;i++){
                if(ch[i]=='(')
                    x++;
                if(ch[i]==')')
                    y++;
            }
            if(x<=y)
                b=false;
            return b;
        }
        private StringBuilder MoreLeftBracket(StringBuilder s){
            char[] ch = s.toString().toCharArray();
            int x=0,y=0;
            for(int i = 0;i<ch.length;i++){
                if(ch[i]=='(')
                    x++;
                if(ch[i]==')')
                    y++;
            }
            if(x>y){
                for(int i = 0 ; i< x-y;i++)
                    s.append(")");
            }
            return s;
        }
    }
    
    

     

  4.  中缀表达式转后缀表达式并对其求值:(我自己掌握的不够充分,感觉对整数的相关算法理解了,但是在写浮点数的相关算法时还是出了点问题,在这里借用到是别人的代码)
    在项目中新建一个infixToDuffix的Java文件,代码如下:

    public class InfixToPostfix {
        //使用集合定义好符号的运算优先级别
        private static final Map<Character, Integer> basic = new HashMap<Character, Integer>();
    
        static {
            basic.put('-', 1);
            basic.put('+', 1);
            basic.put('*', 2);
            basic.put('/', 2);
            basic.put('(', 0);//在运算中  ()的优先级最高,但是此处因程序中需要 故设置为0
        }
    
    
        //将中缀表达式转换为后缀表达式
        public static String toSuffix(StringBuilder infix) {
            List<String> queue = new ArrayList<String>();                                    //定义队列  用于存储 数字  以及最后的  后缀表达式
            List<Character> stack = new ArrayList<Character>();                             //定义栈    用于存储  运算符  最后stack中会被 弹空
            //                                      trim()用于去掉开头结尾的空格
            char[] charArr = infix.substring(0, infix.length()).trim().toCharArray();                                    //字符数组  用于拆分数字或符号
            String standard = "*/+-()";                                                        //判定标准 将表达式中会出现的运算符写出来
            char ch = '&';                                                                    //在循环中用来保存 字符数组的当前循环变量的  这里仅仅是初始化一个值  没有意义
            int len = 0;                                                                 //用于记录字符长度 【例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字】
            for (int i = 0; i < charArr.length; i++) {//开始迭代
                int last = 0;
                if (i > 0) {
                    last = charArr[i - 1];
                }
                ch = charArr[i];                                                            //保存当前迭代变量
                if (Character.isDigit(ch)) {                                                    //如果当前变量为 数字
                    len++;
                } else if (ch == '.') {                                                        //如果当前变量为  .  会出现在小数里面
                    len++;
                }
    
                else if (ch == '-' && (last == '*' || last == '/' || i == 0)) {                                                        //如果当前变量为  .  会出现在小数里面
                    len++;
                    continue;
                }
                else if (standard.indexOf(ch) != -1) {                                        //如果是上面标准中的 任意一个符号
                    if (len > 0) {                                                            //长度也有
                        queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len, i)));    //说明符号之前的可以截取下来做数字
                        len = 0;                                                            //长度置空
                    }
                    if (ch == '(') {                                                            //如果是左括号
                        stack.add(ch);                                                        //将左括号 放入栈中
                        continue;                                                            //跳出本次循环  继续找下一个位置
                    }
    
                    if (!stack.isEmpty()) {                                                    //如果栈不为empty
                        int size = stack.size() - 1;                                        //获取栈的大小-1  即代表栈最后一个元素的下标
                        boolean flag = false;                                                //设置标志位
                        while (size >= 0 && ch == ')' && stack.get(size) != '(') {            //若当前ch为右括号,则 栈里元素从栈顶一直弹出,直到弹出到 左括号
                            queue.add(String.valueOf(stack.remove(size)));                    //注意此处条件:ch并未入栈,所以并未插入队列中;同样直到找到左括号的时候,循环结束了,所以左括号也不会放入队列中【也就是:后缀表达式中不会出现括号】
                            size--;                                                            //size-- 保证下标永远在栈最后一个元素【栈中概念:指针永远指在栈顶元素】
                            flag = true;                                                    //设置标志位为true  表明一直在取()中的元素
                        }
                        if (ch == ')' && stack.get(size) == '(') {
                            flag = true;
                        }
                        while (size >= 0 && !flag && basic.get(stack.get(size)) >= basic.get(ch)) {    //若取得不是()内的元素,并且当前栈顶元素的优先级>=对比元素 那就出栈插入队列
                            queue.add(String.valueOf(stack.remove(size)));                    //同样  此处也是remove()方法,既能得到要获取的元素,也能将栈中元素移除掉
                            size--;
                        }
                    }
                    if (ch != ')') {                                                            //若当前元素不是右括号
                        stack.add(ch);                                                        //就要保证这个符号 入栈
                    } else {                                                                //否则就要出栈 栈内符号
                        stack.remove(stack.size() - 1);
                    }
                }
                if (i == charArr.length - 1) {                                                //如果已经走到了  中缀表达式的最后一位
                    if (len > 0) {                                                            //如果len>0  就截取数字
                        queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1)));
                    }
                    int size = stack.size() - 1;                                            //size表示栈内最后一个元素下标
                    while (size >= 0) {                                                        //一直将栈内  符号全部出栈 并且加入队列中  【最终的后缀表达式是存放在队列中的,而栈内最后会被弹空】
                        queue.add(String.valueOf(stack.remove(size)));
                        size--;
                    }
                }
    
            }
            String a = queue.toString();
            return a.substring(1, a.length() - 1);
        }
    
    
        public static String dealEquation(String equation){
    
            String [] arr = equation.split(", ");                                    //根据, 拆分字符串
            List<String> list = new ArrayList<String>();//用于计算时  存储运算过程的集合【例如list中当前放置  100   20  5  /  则取出20/5 最终将结果4存入list   此时list中结果为  100  4 】
    
    
            for (int i = 0; i < arr.length; i++) {                                    //此处就是上面说的运算过程, 因为list.remove的缘故,所以取出最后一个数个最后两个数  都是size-2
                int size = list.size();
                switch (arr[i]) {
                    case "+": BigDecimal a = new BigDecimal(list.remove(size-2)).add(new BigDecimal(list.remove(size-2))); list.add(String.valueOf(a));     break;
                    case "-": BigDecimal b = new BigDecimal(list.remove(size-2)).subtract(new BigDecimal(list.remove(size-2))); list.add(String.valueOf(b));     break;
                    case "*": BigDecimal c = new BigDecimal(list.remove(size-2)).multiply(new BigDecimal(list.remove(size-2))); list.add(String.valueOf(c));     break;
                    case "/": BigDecimal d = new BigDecimal(list.remove(size-2)).divide(new BigDecimal(list.remove(size-2)),10,BigDecimal.ROUND_HALF_UP); list.add(String.valueOf(d));       break;
                    default: list.add(arr[i]);     break;                                    //如果是数字  直接放进list中
                }
            }
            return list.size() == 1 ? list.get(0) : "运算失败" ;                    //最终list中仅有一个结果,否则就是算错了
        }
    }
    

    还有不足的会慢慢改正的。 

     

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值