本次APP的源碼已上傳到我的GitHub:https://github.com/zdm-code/Android-learning/tree/master/android_learning/app
經過長達兩天的Android的學習,覺得已經可以做一些簡單的小APP練練手。本次就做了一個簡易計算器,下面簡單記錄一下開發過程。
本次開發運用了前幾次關於Android博文里的一些內容。主要使用了幾個基本的控件,通過drawable設計控件樣式,通過線性布局將所有控件串聯起來。
計算器是人們生活中最常用的工具之一,無論在電腦上還是手機上,都少不了計算器的身影。原本以為計算器的開發還是蠻簡單的,結果在前端寫好之后,一進入activity的java代碼編寫就發現了很多細節問題。如:用戶非法數據的輸入判斷(例如00012,1.23.45,1+*3等等)以及用戶體驗等,通過簡單的點擊打印的方式會很容易導致數據不合法,因此后台需要判斷並控制用戶的輸入數據。
先來簡單對比一下手機自帶的計算器和自己開發的計算器
如圖所見,樣子還是比較相似的(其實是照着手機上自帶的樣子開發的)。我的計算器有三部分組成:標題,顯示區(TextView),按鍵區(Button),它能實現基本的加減乘除運算功能(包括連續表達式的求值),體驗感已和手機自帶計算器基本一致。
這里不再給出布局代碼,僅附上activity的java代碼
1 package com.example.animator.android_learning; 2 3 import android.content.Context; 4 import android.support.v7.app.ActionBarActivity; 5 import android.os.Bundle; 6 import android.util.DisplayMetrics; 7 import android.view.View; 8 import android.view.WindowManager; 9 import android.widget.Button; 10 import android.widget.TextView; 11 import android.widget.Toast; 12 13 import com.example.animator.utils.Calculator; 14 import com.example.animator.utils.IsSecondNumZero; 15 16 public class MainActivity extends ActionBarActivity implements View.OnClickListener { 17 18 TextView textView; 19 Button btn_1; 20 Button btn_2; 21 Button btn_3; 22 Button btn_4; 23 Button btn_5; 24 Button btn_6; 25 Button btn_7; 26 Button btn_8; 27 Button btn_9; 28 Button btn_10; 29 Button btn_11; 30 Button btn_12; 31 Button btn_13; 32 Button btn_14; 33 Button btn_15; 34 Button btn_16; 35 Button btn_17; 36 Button btn_18; 37 Button btn_19; 38 39 @Override 40 protected void onCreate(Bundle savedInstanceState) { 41 super.onCreate(savedInstanceState); 42 setContentView(R.layout.activity_main); 43 textView= (TextView) findViewById(R.id.tv_show); 44 btn_1= (Button) findViewById(R.id.btn_1); 45 btn_2= (Button) findViewById(R.id.btn_2); 46 btn_3= (Button) findViewById(R.id.btn_3); 47 btn_4= (Button) findViewById(R.id.btn_4); 48 btn_5= (Button) findViewById(R.id.btn_5); 49 btn_6= (Button) findViewById(R.id.btn_6); 50 btn_7= (Button) findViewById(R.id.btn_7); 51 btn_8= (Button) findViewById(R.id.btn_8); 52 btn_9= (Button) findViewById(R.id.btn_9); 53 btn_10= (Button) findViewById(R.id.btn_10); 54 btn_11= (Button) findViewById(R.id.btn_11); 55 btn_12= (Button) findViewById(R.id.btn_12); 56 btn_13= (Button) findViewById(R.id.btn_13); 57 btn_14= (Button) findViewById(R.id.btn_14); 58 btn_15= (Button) findViewById(R.id.btn_15); 59 btn_16= (Button) findViewById(R.id.btn_16); 60 btn_17= (Button) findViewById(R.id.btn_17); 61 btn_18= (Button) findViewById(R.id.btn_18); 62 btn_19= (Button) findViewById(R.id.btn_19); 63 64 btn_1.setOnClickListener(this); 65 btn_2.setOnClickListener(this); 66 btn_3.setOnClickListener(this); 67 btn_4.setOnClickListener(this); 68 btn_5.setOnClickListener(this); 69 btn_6.setOnClickListener(this); 70 btn_7.setOnClickListener(this); 71 btn_8.setOnClickListener(this); 72 btn_9.setOnClickListener(this); 73 btn_10.setOnClickListener(this); 74 btn_11.setOnClickListener(this); 75 btn_12.setOnClickListener(this); 76 btn_13.setOnClickListener(this); 77 btn_14.setOnClickListener(this); 78 btn_15.setOnClickListener(this); 79 btn_16.setOnClickListener(this); 80 btn_17.setOnClickListener(this); 81 btn_18.setOnClickListener(this); 82 btn_19.setOnClickListener(this); 83 84 85 86 } 87 88 89 //根據手機的分辨率從dp單位轉換成px單位 90 public static int dip2px(Context context,float dpValue){ 91 //獲取當前手機的像素密度 92 final float scale=context.getResources().getDisplayMetrics().density; 93 return (int)(dpValue*scale+0.5f); //四舍五入取整 94 } 95 96 //根據手機的分辨率從px單位轉換成dp單位 97 public static int px2dip(Context context,float pxValue){ 98 //獲取當前手機的像素密度 99 final float scale=context.getResources().getDisplayMetrics().density; 100 return (int)(pxValue/scale+0.5f); //四舍五入取整 101 } 102 103 public static int getScreenWidth(Context context){ 104 //從系統服務中獲取窗口管理器 105 WindowManager windowManager=(WindowManager)context.getSystemService(context.WINDOW_SERVICE); 106 DisplayMetrics displayMetrics=new DisplayMetrics(); 107 //從默認顯示器中獲取顯示參數保存到displayMetrics對象中 108 windowManager.getDefaultDisplay().getMetrics(displayMetrics); 109 return displayMetrics.widthPixels; //返回屏幕的寬度數值 110 } 111 112 public static int getScreenHeight(Context context){ 113 //從系統服務中獲取窗口管理器 114 WindowManager windowManager=(WindowManager)context.getSystemService(context.WINDOW_SERVICE); 115 DisplayMetrics displayMetrics=new DisplayMetrics(); 116 //從默認顯示器中獲取顯示參數保存到displayMetrics對象中 117 windowManager.getDefaultDisplay().getMetrics(displayMetrics); 118 return displayMetrics.heightPixels; //返回屏幕的高度數值 119 } 120 121 public static float getScreenDensity(Context context){ 122 //從系統服務中獲取窗口管理器 123 WindowManager windowManager=(WindowManager)context.getSystemService(context.WINDOW_SERVICE); 124 DisplayMetrics displayMetrics=new DisplayMetrics(); 125 //從默認顯示器中獲取顯示參數保存到displayMetrics對象中 126 windowManager.getDefaultDisplay().getMetrics(displayMetrics); 127 return displayMetrics.density; //返回屏幕的高度數值 128 } 129 130 @Override 131 public void onClick(View view) { 132 String text=textView.getText().toString(); 133 String[] number=text.split("[+|-|*|/|=]"); 134 String lastnumber=""; 135 if(number.length>0) 136 lastnumber=number[number.length-1]; 137 switch (view.getId()){ 138 case R.id.btn_1: 139 case R.id.btn_16://刪除數字鍵,計算完畢后點擊全部清除,表達式書寫中則去除最后一個字符 140 if(text.contains("=")){ 141 textView.setText(""); 142 }else { 143 if (text.length() > 0) 144 textView.setText(text.substring(0, text.length() - 1)); 145 } 146 break; 147 case R.id.btn_2: 148 //除號鍵,判定是否計算完成,若完成則取結果繼續運算 149 if(text.length()>0) { 150 if(text.contains("=")){ 151 textView.setText(lastnumber+"/"); 152 } 153 //判斷前面字符是否為符號,若是,則將其改為當前輸入符號(注意兩符號不能同時出現) 154 else { 155 if (text.substring(text.length() - 1).equals("+") == false && text.substring(text.length() - 1).equals("-") == false && text.substring(text.length() - 1).equals("*") == false && 156 text.substring(text.length() - 1).equals("/") == false && text.substring(text.length() - 1).equals(".") == false) 157 textView.setText(text + "/"); 158 else if (text.substring(text.length() - 1).equals("+") == true || text.substring(text.length() - 1).equals("-") == true || text.substring(text.length() - 1).equals("*") == true || 159 text.substring(text.length() - 1).equals("/") == true) 160 textView.setText(text.substring(0, text.length() - 1) + "/"); 161 } 162 } 163 break; 164 case R.id.btn_3: 165 //乘號鍵,用法大致同除號 166 if(text.length()>0) { 167 if(text.contains("=")){ 168 textView.setText(lastnumber+"*"); 169 } 170 else { 171 if (text.substring(text.length() - 1).equals("+") == false && text.substring(text.length() - 1).equals("-") == false && text.substring(text.length() - 1).equals("*") == false && 172 text.substring(text.length() - 1).equals("/") == false && text.substring(text.length() - 1).equals(".") == false) 173 textView.setText(text + "*"); 174 else if (text.substring(text.length() - 1).equals("+") == true || text.substring(text.length() - 1).equals("-") == true || text.substring(text.length() - 1).equals("*") == true || 175 text.substring(text.length() - 1).equals("/") == true) 176 textView.setText(text.substring(0, text.length() - 1) + "*"); 177 } 178 } 179 break; 180 case R.id.btn_4: 181 //全部清除鍵 182 textView.setText(""); 183 break; 184 case R.id.btn_5: 185 //數字7,判斷組合數字首位是否為0,若是,則將其置為7,下面數字用法類似 186 if(text.contains("=")) 187 { 188 textView.setText("7"); 189 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 190 { 191 textView.setText(text.substring(0, text.length() - 1) + "7"); 192 }else 193 textView.setText(text+"7"); 194 break; 195 case R.id.btn_6: 196 if(text.contains("=")) 197 { 198 textView.setText("8"); 199 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 200 { 201 textView.setText(text.substring(0, text.length() - 1) + "8"); 202 }else 203 textView.setText(text+"8"); 204 break; 205 case R.id.btn_7: 206 if(text.contains("=")) 207 { 208 textView.setText("9"); 209 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 210 { 211 textView.setText(text.substring(0, text.length() - 1) + "9"); 212 }else 213 textView.setText(text+"9"); 214 break; 215 case R.id.btn_8: 216 if(text.length()>0) { 217 if(text.contains("=")){ 218 textView.setText(lastnumber+"+"); 219 } 220 else { 221 if (text.substring(text.length() - 1).equals("+") == false && text.substring(text.length() - 1).equals("-") == false && text.substring(text.length() - 1).equals("*") == false && 222 text.substring(text.length() - 1).equals("/") == false && text.substring(text.length() - 1).equals(".") == false) 223 textView.setText(text + "+"); 224 else if (text.substring(text.length() - 1).equals("+") == true || text.substring(text.length() - 1).equals("-") == true || text.substring(text.length() - 1).equals("*") == true || 225 text.substring(text.length() - 1).equals("/") == true) 226 textView.setText(text.substring(0, text.length() - 1) + "+"); 227 } 228 } 229 break; 230 case R.id.btn_9: 231 if(text.contains("=")) 232 { 233 textView.setText("4"); 234 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 235 { 236 textView.setText(text.substring(0, text.length() - 1) + "4"); 237 }else 238 textView.setText(text+"4"); 239 break; 240 case R.id.btn_10: 241 if(text.contains("=")) 242 { 243 textView.setText("5"); 244 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 245 { 246 textView.setText(text.substring(0, text.length() - 1) + "5"); 247 }else 248 textView.setText(text+"5"); 249 break; 250 case R.id.btn_11: 251 if(text.contains("=")) 252 { 253 textView.setText("6"); 254 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 255 { 256 textView.setText(text.substring(0, text.length() - 1) + "6"); 257 }else 258 textView.setText(text+"6"); 259 break; 260 case R.id.btn_12: 261 if(text.length()>0) { 262 if(text.contains("=")){ 263 textView.setText(lastnumber+"-"); 264 } 265 else { 266 if (text.substring(text.length() - 1).equals("+") == false && text.substring(text.length() - 1).equals("-") == false && text.substring(text.length() - 1).equals("*") == false && 267 text.substring(text.length() - 1).equals("/") == false && text.substring(text.length() - 1).equals(".") == false) 268 textView.setText(text + "-"); 269 else if (text.substring(text.length() - 1).equals("+") == true || text.substring(text.length() - 1).equals("-") == true || text.substring(text.length() - 1).equals("*") == true || 270 text.substring(text.length() - 1).equals("/") == true) 271 textView.setText(text.substring(0, text.length() - 1) + "-"); 272 } 273 } 274 break; 275 case R.id.btn_13: 276 if(text.contains("=")) 277 { 278 textView.setText("1"); 279 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 280 { 281 textView.setText(text.substring(0, text.length() - 1) + "1"); 282 }else 283 textView.setText(text+"1"); 284 break; 285 case R.id.btn_14: 286 if(text.contains("=")) 287 { 288 textView.setText("2"); 289 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 290 { 291 textView.setText(text.substring(0, text.length() - 1) + "2"); 292 }else 293 textView.setText(text+"2"); 294 break; 295 case R.id.btn_15: 296 if(text.contains("=")) 297 { 298 textView.setText("3"); 299 }else if((text.length()>2&&text.charAt(text.length()-1)=='0'&&isOperation(text.charAt(text.length()-2)))||(text.length()==1&&text.charAt(0)=='0')) 300 { 301 textView.setText(text.substring(0, text.length() - 1) + "3"); 302 }else 303 textView.setText(text+"3"); 304 break; 305 case R.id.btn_17: 306 if(text.contains("=")) 307 { 308 textView.setText("0"); 309 }else { 310 //判斷當前數字是否僅為“0”,即不包含小數點,數字頭不能出現多個0 311 if (lastnumber.equals("0") == false) 312 textView.setText(text + "0"); 313 } 314 break; 315 case R.id.btn_18: 316 //小數點,判斷是否計算完成,若是,則打印0. 317 if(text.contains("=")) 318 { 319 textView.setText("0."); 320 }else if(lastnumber.contains(".")==false){//保證同一數字里只有一個小數點 321 if (text.length() > 0) { 322 if (text.substring(text.length() - 1).equals("+") == false && text.substring(text.length() - 1).equals("-") == false && text.substring(text.length() - 1).equals("*") == false && 323 text.substring(text.length() - 1).equals("/") == false && text.substring(text.length() - 1).equals(".") == false) 324 textView.setText(text + "."); 325 else if (text.substring(text.length() - 1).equals("+") == true || text.substring(text.length() - 1).equals("-") == true || text.substring(text.length() - 1).equals("*") == true || 326 text.substring(text.length() - 1).equals("/") == true) 327 textView.setText(text + "0."); 328 } else { 329 textView.setText("0."); 330 } 331 } 332 break; 333 case R.id.btn_19: 334 if(text.contains("=")==false) { 335 if (IsSecondNumZero.isAvailable(text + "=")) {//判斷除法是除數為0的情況 336 Toast.makeText(MainActivity.this, "除數不能為0", Toast.LENGTH_LONG).show(); 337 } else {//通過棧進行結果運算 338 Calculator calculator = new Calculator(); 339 String result = calculator.convertDoubleToString(calculator.calculate(text)); 340 textView.setText(text + "=" + result); 341 } 342 } 343 break; 344 } 345 } 346 347 public boolean isOperation(char c){ 348 return c=='+'||c=='-'||c=='*'||c=='/'; 349 } 350 }
其中有一些冗余的代碼,讀者可自行縮減。
APP中通過棧來進行表達式求值的工具類借鑒如下博客:https://blog.csdn.net/qq_40378034/article/details/100112130?utm_source=app,並對博客中首數字負數報錯的部分進行了修改。
下面再附上除法判斷除數為0的代碼(由於是最后求值,表達式中可能有多個除號,所以需要遍歷所有除號)
1 package com.example.animator.utils; 2 3 import android.util.Log; 4 5 import java.math.BigDecimal; 6 import java.util.ArrayList; 7 8 /** 9 * Created by animator on 2020/1/14. 10 */ 11 public class IsSecondNumZero { 12 public static boolean isAvailable(String str){ 13 ArrayList<Integer> divlist=new ArrayList<>();//儲存除號索引 14 ArrayList<Integer> alllist=new ArrayList<>();//儲存所有運算符索引 15 16 for(int i=0;i<str.length();i++) 17 { 18 if(str.charAt(i)=='/') 19 { 20 divlist.add(i); 21 alllist.add(i); 22 } 23 else if(str.charAt(i)=='+'||str.charAt(i)=='-'||str.charAt(i)=='*'||str.charAt(i)=='=') 24 { 25 alllist.add(i); 26 } 27 } 28 Log.v("divsize",divlist.size()+""); 29 Log.v("allsize",alllist.size()+""); 30 for(int i=0;i<divlist.size();i++){ 31 String string=str.substring(divlist.get(i)+1,alllist.get(alllist.indexOf(divlist.get(i)) + 1)); 32 BigDecimal num = new BigDecimal(string); 33 if(num.compareTo(new BigDecimal("0"))==0) 34 return true; 35 } 36 return false; 37 38 } 39 }