Android计算器代码分析
16lz
2021-12-04
前言
学习Android写的第一个app,前前后后用了近一周的时间,建议刚开始写的先预算好自己要处理的异常,最好全面详细的列出来,避免和我一样后期花费很大功夫进行各种预算处理。接下来分享一下我做的计算器。
真机测试如下
效果渲染
按钮点击变色
首先在Android Studio(app/src/main/res/drawable)文件夹中创建一个Drawable resource file,这里我创建的是change.xml,change1.xml(因为我的按钮背景有两个颜色所以创建两个),在Button添加背景时使用,修改代码如下
这里的drawable="@color/colorPrimary",可在res/values/colors.xml中添加你自己喜欢的,添加后可这样使用
<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/colorPrimary" android:state_enabled="true"//接受触摸或者点击事件 android:state_pressed="true"//被点击时 /> <item android:drawable="@color/colorchange0" android:state_enabled="true" android:state_pressed="false"/> //未被点击时</selector>
字体自适应显示框而改变大小
先看效果
这里建议使用autoSizeTextType=“uniform”//字体自适应功能一两行就搞定(做完才知道的,不懂得可百度)
我在这里是使用了多线程(网上看到如果直接用getLineCount()方法,获取的行数不准确),在多线性中获取getLineCount()获取此时的行数,然后经过一系列的判断设置setTextSize(),注意:这种方法在按C/del时要做判断
textView_1.post(new Runnable() { @Override public void run() { int line = textView_1.getLineCount(); if(line==1 && flag3==0){ textView_1.setTextSize(80); flag3 = 1;//这里是我定义的用于判断行数的全局变量 } if(line==2 && flag1==0){ length1 = str.length()-1; Log.d("mainActivity","length1"+ +length1); textView_1.setTextSize(60); flag1 = 1; } if(line==3 && flag2==0){ length2 = str.length()-1; Log.d("mainActivity","length2"+ +length2); textView_1.setTextSize(40); flag2 = 1; } } });
布局文件
这里我用的线性布局,相对简单,里面嵌套6个线性布局,对应布局中的文本区和六行按钮。
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFFFFF" > <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="3"> <TextView android:id="@+id/TextView_1" android:layout_width="match_parent" android:layout_height="match_parent" android:textSize="80dp" android:maxLines="3" android:gravity="bottom|right" /> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:orientation="horizontal" android:layout_marginBottom="7dp" android:layout_weight="1"> <Button android:id="@+id/button_c" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:textColor="#00CC00" android:background="@drawable/change1" android:text="C"/> <Button android:id="@+id/button_divede" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:textColor="#00CC00" android:background="@drawable/change1" android:text="/"/> <Button android:id="@+id/button_multiply" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00CC00" android:layout_marginRight="7dp" android:background="@drawable/change1" android:text="*"/> <Button android:id="@+id/button_del" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00CC00" android:background="@drawable/change1" android:text="Del"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:background="#FFFFFF" android:layout_marginBottom="7dp" android:layout_weight="1"> <Button android:id="@+id/button_7" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/change" android:layout_marginRight="7dp" android:text="7"/> <Button android:id="@+id/button_8" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/change" android:layout_marginRight="7dp" android:text="8"/> <Button android:id="@+id/button_9" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="9"/> <Button android:id="@+id/button_reduce" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00cc00" android:background="@drawable/change1" android:text="-"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="7dp" android:layout_weight="1"> <Button android:id="@+id/button_4" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="4"/> <Button android:id="@+id/button_5" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="5"/> <Button android:id="@+id/button_6" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="6"/> <Button android:id="@+id/button_add" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00FF00" android:background="@drawable/change1" android:text="+"/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="7dp" android:layout_weight="1"> <Button android:id="@+id/button_1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="1"/> <Button android:id="@+id/button_2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="2"/> <Button android:id="@+id/button_3" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="3"/> <Button android:id="@+id/button_point" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:background="@drawable/change1" android:textColor="#00CC00" android:text="."/> </LinearLayout> <LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginBottom="7dp" android:layout_weight="1"> <Button android:id="@+id/button_leftparenthesis" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change1" android:textColor="#00CC00" android:text="("/> <Button android:id="@+id/button_0" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:layout_marginRight="7dp" android:background="@drawable/change" android:text="0"/> <Button android:id="@+id/button_rightparenthesis" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00CC00" android:layout_marginRight="7dp" android:background="@drawable/change1" android:text=")"/> <Button android:id="@+id/button_equals" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1" android:textColor="#00CC00" android:background="@drawable/change1" android:text="="/> </LinearLayout></LinearLayout>
MainActivity
处理的异常
-
当输入“-”时,如果代表负号,此时,屏幕显示的应该是“(-”
-
对于a(b)这种形式,自动补成a*(b),对于(a)b,自动补成(a)*b
-
除零异常提醒
-
删除负号时,击一下del,删除两个字符
-
对于.a应补充成0.a
-
对于左右括号数不相等的,给予提示
-
对于输入异常的不予执行,如输入1.2后不能再输’.’ ,输入0000显示一个零
-
等等…
代码
package com.example.calculator;import androidx.appcompat.app.AppCompatActivity;import android.graphics.Color;import android.graphics.drawable.Drawable;import android.os.Bundle;import android.util.Log;import android.view.View;import android.view.ViewTreeObserver;import android.widget.Button;import android.widget.TextView;import android.widget.Toast;public class MainActivity extends AppCompatActivity implements View.OnClickListener{ private int flag1 = 0; private int flag2 = 0; private int flag3 = 0; private int length1 = 0; private int length2 = 0; private int IShaveleftparenthesis = 0; //标记是否出现左括号 private boolean ISnegative_sign = false; //是否是负号 private boolean ISpiece = false; //是否要加( private boolean ISmanyzero = true; private String str; private Button button_0; private Button button_1; private Button button_2; private Button button_3; private Button button_4; private Button button_5; private Button button_6; private Button button_7; private Button button_8; private Button button_9; private Button button_point; //"." private Button button_add; private Button button_reduce; private Button button_multiply; private Button button_divede; private Button button_c; //"清除" private Button button_del; //"删除" private Button button_equals; private Button button_leftparenthesis; //"(" private Button button_rightparenthesis; //")" private TextView textView_1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { button_0 = (Button)findViewById(R.id.button_0); button_1 = (Button)findViewById(R.id.button_1); button_2 = (Button)findViewById(R.id.button_2); button_3 = (Button)findViewById(R.id.button_3); button_4 = (Button)findViewById(R.id.button_4); button_5 = (Button)findViewById(R.id.button_5); button_6 = (Button)findViewById(R.id.button_6); button_7 = (Button)findViewById(R.id.button_7); button_8 = (Button)findViewById(R.id.button_8); button_9 = (Button)findViewById(R.id.button_9); button_point = (Button)findViewById(R.id.button_point); button_add = (Button)findViewById(R.id.button_add); button_reduce = (Button)findViewById(R.id.button_reduce); button_multiply = (Button)findViewById(R.id.button_multiply); button_divede = (Button)findViewById(R.id.button_divede); button_c = (Button)findViewById(R.id.button_c); button_del = (Button)findViewById(R.id.button_del); button_equals = (Button)findViewById(R.id.button_equals); button_leftparenthesis = (Button)findViewById(R.id.button_leftparenthesis); button_rightparenthesis = (Button)findViewById(R.id.button_rightparenthesis); textView_1 = (TextView)findViewById(R.id.TextView_1); button_0.setOnClickListener(this); button_1.setOnClickListener(this); button_2.setOnClickListener(this); button_3.setOnClickListener(this); button_4.setOnClickListener(this); button_5.setOnClickListener(this); button_6.setOnClickListener(this); button_7.setOnClickListener(this); button_8.setOnClickListener(this); button_9.setOnClickListener(this); button_point.setOnClickListener(this); button_add.setOnClickListener(this); button_reduce.setOnClickListener(this); button_multiply.setOnClickListener(this); button_divede.setOnClickListener(this); button_equals.setOnClickListener(this); button_c.setOnClickListener(this); button_del.setOnClickListener(this); button_leftparenthesis.setOnClickListener(this); button_rightparenthesis.setOnClickListener(this); } @Override public void onClick(View view) { str = textView_1.getText().toString(); textView_1.post(new Runnable() { @Override public void run() { int line = textView_1.getLineCount(); if(line==1 && flag3==0){ textView_1.setTextSize(80); flag3 = 1; } if(line==2 && flag1==0){ length1 = str.length()-1; Log.d("mainActivity","length1"+ +length1); textView_1.setTextSize(60); flag1 = 1; } if(line==3 && flag2==0){ length2 = str.length()-1; Log.d("mainActivity","length2"+ +length2); textView_1.setTextSize(40); flag2 = 1; } } }); if(str.length()==0 || str.charAt(str.length()-1)!= '0') { ISmanyzero = true; } switch (view.getId()){ case R.id.button_0: if(str.length()==0||str.charAt(str.length()-1)!='/'){ if(str.length()==0|| ( !Character.isDigit(str.charAt(str.length()-1)) && str.charAt(str.length()-1)!='.')) { str += "0"; ISmanyzero = false; } if(ISmanyzero==true) { if(str.length()==1&&str.charAt(0)=='0'){ ISmanyzero = false; break; } str += "0"; } textView_1.setText(str); }else{ Toast.makeText(MainActivity.this,"不能除以0",Toast.LENGTH_SHORT).show(); } break; case R.id.button_1: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*1"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="1"; } textView_1.setText(str); break; case R.id.button_2: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*2"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="2"; } textView_1.setText(str); break; case R.id.button_3: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*3"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="3"; } textView_1.setText(str); break; case R.id.button_4: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*4"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="4"; } textView_1.setText(str); break; case R.id.button_5: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*5"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="5"; } textView_1.setText(str); break; case R.id.button_6: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*6"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="6"; } textView_1.setText(str); break; case R.id.button_7: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*7"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="7"; } textView_1.setText(str); break; case R.id.button_8: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*8"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="8"; } textView_1.setText(str); break; case R.id.button_9: if(str.length()!=0&&str.charAt(str.length()-1)==')') str+="*9"; else{ if(!ISmanyzero) str = str.substring(0,str.length()-1); str+="9"; } textView_1.setText(str); break; case R.id.button_point: if(str.length()>0 && !Character.isDigit(str.charAt(str.length()-1)) ) break; if(str.length()==0){ str += "0."; } else{ int len = str.length()-1; while(len>=0&&Character.isDigit(str.charAt(len)) ){ len--; }; if(len>=0&&str.charAt(len)=='.') break; else { str += "."; } } textView_1.setText(str); break; case R.id.button_add: if(str.length()!=0 && ( str.charAt(str.length()-1)==')' || Character.isDigit(str.charAt(str.length()-1))) ) { if (ISpiece) { str += ")+"; ISpiece = false; } else str += "+"; } textView_1.setText(str); break; case R.id.button_reduce: if(str.length()==0 || str.charAt(str.length()-1)=='('){ ISnegative_sign = true; str+="-"; } else if(str.charAt(str.length()-1)==')'||Character.isDigit(str.charAt(str.length()-1))){ if(ISpiece){ str+=")-"; IShaveleftparenthesis--; ISpiece = false; }else{ str+="-"; ISnegative_sign = false; } }else if( str.length()-2>=0 && ( Character.isDigit(str.charAt(str.length()-2)) || str.charAt(str.length()-2)==')')) { str += "(-"; IShaveleftparenthesis++; ISpiece = true; ISnegative_sign = true; } textView_1.setText(str); break; case R.id.button_multiply: if(str.length()!=0 && ( str.charAt(str.length()-1)==')' || Character.isDigit(str.charAt(str.length()-1))) ) { if (ISpiece) { str += ")*"; IShaveleftparenthesis--; ISpiece = false; } else{ str += "*"; } } textView_1.setText(str); break; case R.id.button_divede: if(str.length()!=0 && ( str.charAt(str.length()-1)==')' || Character.isDigit(str.charAt(str.length()-1))) ){ if(ISpiece){ str+=")/"; IShaveleftparenthesis--; ISpiece = false; }else str+="/"; } textView_1.setText(str); break; case R.id.button_equals: if(IShaveleftparenthesis!=0){ Toast.makeText(MainActivity.this,"请补充右括号",Toast.LENGTH_SHORT).show(); break; } if(str.length()==0) break; if(ISpiece){ str+=")"; IShaveleftparenthesis--; ISpiece = false; } try { String s = Core_Algorithm.result2(Core_Algorithm.result1(str)); textView_1.setText(s); str = s; }catch (Exception p){ Toast.makeText(MainActivity.this,"输入错误",Toast.LENGTH_SHORT).show(); } break; case R.id.button_leftparenthesis: if(str.length()==0) { str+="("; IShaveleftparenthesis ++; } else if( str.charAt(str.length()-1)!=')') { if( !Character.isDigit(str.charAt(str.length()-1)) ) str+="("; else{ if(ISpiece){ str+=")*("; ISpiece = false; } else { str += "*("; ISpiece = true; } } IShaveleftparenthesis ++; } textView_1.setText(str); break; case R.id.button_rightparenthesis: if(str.length()!=0 && IShaveleftparenthesis >0 && ( str.charAt(str.length()-1)==')' || Character.isDigit(str.charAt(str.length()-1)) ) ) { if(ISpiece){ ISpiece = false; } str += ")"; IShaveleftparenthesis --; } textView_1.setText(str); break; case R.id.button_c: flag1 = flag2 = flag3 = 0; str = ""; IShaveleftparenthesis = 0; //标记是否出现左括号 ISpiece = false; //是否要加( textView_1.setText(str); break; case R.id.button_del: if(str.length()==0||str.length()==1){ str = ""; IShaveleftparenthesis = 0; } else{ if(str.charAt(str.length()-1)=='('){ if(ISpiece) ISpiece = false; IShaveleftparenthesis--; } else if(str.charAt(str.length()-1)==')') IShaveleftparenthesis++; str = str.substring(0,str.length()-1); if(str.charAt(str.length()-1)=='-'&& ISnegative_sign) str = str.substring(0,str.length()-1); } if(str.length()<=length1) { flag3 = 0; flag1 = 0; } else if(str.length()<=length2) { flag1 = 0; flag2 = 0; } textView_1.setText(str); break; } }}
Core_Algorithm 核心算法
对计算结果的计算
一般采用中缀转后缀,后缀表达式计算法
对输出结果进行去零处理
在计算时我们一般采用BigDecimal来进行结果的计算,但是当出现除法时他的结果不会进行去零处理,也就是说会出现9/3 =3.000000000000000 这种情况,我这里用正则表达式匹配小数,然后完成去零操作
代码如下
package com.example.calculator;import android.util.Log;import java.math.BigDecimal;import java.util.ArrayDeque;import java.util.ArrayList;public class Core_Algorithm { public static ArrayList<String> result1(String formula){ //传入算式,计算结果返回 //中缀转后缀 ArrayDeque<String> ad = new ArrayDeque<>(); //存放操作符 ArrayList<String> list = new ArrayList<>(); //存放后缀表达式 String temp = ""; for(int i = 0; i < formula.length(); i++){ char c = formula.charAt(i); if( (c=='-'&& i==0 ) || (c=='-'&& formula.charAt(i-1)=='(') ){ //temp+='-'; list.add("0");//如果是负号,变成0- ad.push("-"); } else if(Character.isDigit(c)||c=='.'){ if(i==formula.length()-1) { //如果最后有".",不做处理 if (c != '.') temp += c; list.add(temp); } else if(i==0 && c== '.'){ //如果左前面有小数点,变为0.c temp+="0"+c; }else temp+=c; } else{ if(temp!=""){ list.add(temp); temp = ""; } if(c=='(') ad.push(c+""); //遇到左括号直接入栈 //遇到右括号吧操作符栈中的运算符出栈并在存放表达式的栈中入栈,直到遇到"(" else if(c==')'){ while(!ad.isEmpty()&&!ad.peek().equals("(")){ list.add(ad.pop()); } if(ad.peek().equals("(")) ad.pop(); } //如果是加减乘除 else{ if(list.isEmpty()&&c!='-') continue; switch (c){ case '+': case '-': if(!ad.isEmpty() && priority(ad.peek())>=0){ //ad2.push(ad1.pop()); list.add(ad.pop()); ad.push(c+""); } else{ ad.push(c+""); } break; case '*': case '/': ad.push(c+""); break; } } } } while(!ad.isEmpty()){ //ad2.push(ad1.pop()); list.add(ad.pop()); } if(list.size()==1){ //如果只有一个运算数,变为+0 list.add("0"); list.add("+"); } //Log.d("Core Algo",list.toString()); return list; } public static int priority(String p){ if(p.equals("*") || p.equals("/")){ return 1; }else if(p.equals("+") || p.equals("-")){ return 0; } return -1; } //计算逆波兰表达式 public static String result2(ArrayList<String> list){ ArrayList<String> arr = new ArrayList<>(); for(int i = 0; i < list.size(); i++){ int j = arr.size(); switch (list.get(i)){ case "+": //这里注意:remove后arr.size少一个所以第二个j-2可理解为arr.size()-1-1 BigDecimal a = new BigDecimal(arr.remove(j-2)).add(new BigDecimal(arr.remove(j-2))); arr.add(String.valueOf(a)); break; case "-": BigDecimal b = new BigDecimal(arr.remove(j-2)).subtract(new BigDecimal(arr.remove(j-2))); arr.add(String.valueOf(b)); break; case "*": BigDecimal c = new BigDecimal(arr.remove(j-2)).multiply(new BigDecimal(arr.remove(j-2))); arr.add(String.valueOf(c)); break; case "/": BigDecimal d = new BigDecimal(arr.remove(j - 2)).divide (new BigDecimal(arr.remove(j - 2)), 20, BigDecimal.ROUND_HALF_UP); arr.add(String.valueOf(d)); break; default:arr.add(list.get(i)); break; } } String rt = arr.get(0); if(rt.length()==1) return rt; if(rt.matches("^[\\\\+\\\\-]?([0-9]*[.][0-9]*)$")) { //匹配是否是小数 int i = rt.length() - 1; //匹配成功的去除末尾的0 while (rt.charAt(i) == '0') i--; if (rt.charAt(i) == '.') i--; rt = rt.substring(0, i + 1); } return rt; }}
更多相关文章
- 【android工程转为lib工程后提示'R.id.xxx不能作为case语句的表
- Android计算器——入门
- Android(安卓)超好正则表达式工具类RegexUtil
- Android(安卓)studio使用lambda表达式
- Android媒体库使用分组查询
- android 通话记录次数
- Jetpack学习(二)——databinding(2)
- Android(安卓)Q中外部存储盘路径正则表达式的理解
- 在Android(安卓)Studio中使用Lambda表达式