編輯:關於android開發
項目源碼在文章最後。
這兩天寫了一個Android的計算器,現在整理一下思路與代碼。
首先是功能需求分析:
1、數字我規定最長為九位,如果有小數點則加上小數點最長為十位
2、第二個參數輸入時不允許為負數,但是先得出的結果為負數,可以再進行運算(比如:1-2=-1,結果顯示的是-1,可以再運算,-1+2=1)
3、得出的結果如果大於等於10位,則把數據進行科學計數
4、科學計數的數據不能再進行運算,再按按鈕會直接顯示0或者當前按下的數字
5、進行連續運算時,會先計算先一個運算的結果,在把結果作為第一個參數進行下次運算(比如:1+2+3,當按下第二個加號的時候,會顯示3+,先把前一個運算的結果算出來再進行下一個運算)
6、當除數為0時,顯示 error
7、默認情況下,顯示 0
8、是否進行運算過,判斷是否按下過等於號,如果按下,顯示了結果,再按數字則直接顯示當前數字而不是在結果後添加這個數字
接下來是正式開始編寫代碼:
1、界面布局 (TableLayout 實現按鈕排版 ,EditText 顯示表達式或值)
2、初始化所有控件,以及為需要點擊事件的控件綁定監聽器
3、編寫監聽器事件邏輯代碼
①當按下的是數字,先判斷是否計算過
是(按下過等號):把顯示的文本改為當前按下的數字,計算過的標志設為false
否(沒按過等號):進行下一步判斷,計算過的標志設為false
判斷當前文本是否有科學計數
是(有科學計數的標志 e ):文本置為 0
判斷文本是否只有一個 0
是(當前文本為 0):文本置為空
判斷是否有運算符
是(包含運算符):取出運算符後的第二個參數,進行下一步判斷
判斷最後一個是否是運算符
是(文本最後一個是運算符號):則直接添加按下的數字
否(文本最後一個不是運算符號):進行下一步判斷
判斷第二個參數的長度,包括小數點則可以為10位,不包括小數點只能為9位
否(不包含運算符):判斷第一個參數(即整個文本)的長度,包括小數點則可以為10位,不包括小數點只能為9位
②當按下的是小數點,先判斷是否計算過
是(按下過等號):把文本改為 0. (數字 0 的後面有一個小數點),把計算過的標志位設為 false
否(沒按過等號):進行下一步判斷,,把計算過的標志位設為 false
判斷是否有運算符
是(包含運算符):取出第二個參數,判斷長度是否超過,是:無操作,否:判斷參數中是否已經有小數點,有:無操作,否,添加小數點
否(不包含運算符):判斷第一個參數(即整個文本)的長度是否超過,是:無操作,否:判斷參數中是否已經有小數點,有:無操作,否,添加小數點
③當按下的是特殊鍵(歸零、回退、百分比)
歸零:直接把文本改為 0
回退:判斷文本是否是 error,是:文本改為 0,否:判斷文本的長度,當文本的長度大於0時且不等於1時,文本刪掉最後一個字符,文本長度為1時,文本改為 0
百分比:判斷文本是否是 error,是:無操作,否:判斷是否是表達式,是:無操作,否:數字除百
④當按下的是運算符,判斷當前的文本是否是科學計數
是(文本是科學計數,包含 e):文本置 0
否(文本不是科學計數,不包含 e):判斷文本是否是表達式,且第二個參數不為空
是(是表達式,有兩個參數):先得出結果,如果結果不是 error,添加上相應的運算符,如果結果是 error,無操作
否(不是表達式,可能是數字,也可能是數字後面帶一個運算符):如果計算過的標志位為 true,改為 false,如果最後一個字符為其他運算符,則改為當前按下的運算符,如果最後一個不是當前按下的運算符,則添加改運算符
⑤當按下的是等號,判斷當前文本是否是表達式
是:判斷包含的是哪種運算符,取出兩個參數,如果第二個參數為空,則無操作,如果第二個參數不為空,則進行相應的計算,再把運算結果進行格式化,然後用正則表達式去掉多余的 0 。如果結果的長度大於10位,則把數字轉換成科學計數
布局代碼如下(activity_main.xml):
邏輯部分代碼如下(MainActivity.java):
package com.ikok.calculator; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.EditText; public class MainActivity extends AppCompatActivity implements View.OnClickListener { /** * 數字 */ private Button num0; private Button num1; private Button num2; private Button num3; private Button num4; private Button num5; private Button num6; private Button num7; private Button num8; private Button num9; /** * 運算符 */ private Button plus_btn; private Button subtract_btn; private Button multiply_btn; private Button divide_btn; private Button equal_btn; /** * 其他 */ private Button dot_btn; private Button percent_btn; private Button delete_btn; private Button ac_btn; /** * 結果 */ private EditText mResultText; /** * 已經輸入的字符 */ private String existedText = ""; /** * 是否計算過 */ private boolean isCounted = false; /** * 以負號開頭,且運算符不是是減號 * 例如:-21×2 */ private boolean startWithOperator = false; /** * 以負號開頭,且運算符是減號 * 例如:-21-2 */ private boolean startWithSubtract = false; /** * 不以負號開頭,且包含運算符 * 例如:21-2 */ private boolean noStartWithOperator = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); initEvent(); } /** * 初始化控件 */ private void initView() { /** * 數字 */ num0 = (Button) findViewById(R.id.num_zero); num1 = (Button) findViewById(R.id.num_one); num2 = (Button) findViewById(R.id.num_two); num3 = (Button) findViewById(R.id.num_three); num4 = (Button) findViewById(R.id.num_four); num5 = (Button) findViewById(R.id.num_five); num6 = (Button) findViewById(R.id.num_six); num7 = (Button) findViewById(R.id.num_seven); num8 = (Button) findViewById(R.id.num_eight); num9 = (Button) findViewById(R.id.num_nine); /** * 運算符 */ plus_btn = (Button) findViewById(R.id.plus_btn); subtract_btn = (Button) findViewById(R.id.subtract_btn); multiply_btn = (Button) findViewById(R.id.multiply_btn); divide_btn = (Button) findViewById(R.id.divide_btn); equal_btn = (Button) findViewById(R.id.equal_btn); /** * 其他 */ dot_btn = (Button) findViewById(R.id.dot_btn); percent_btn = (Button) findViewById(R.id.percent_btn); delete_btn = (Button) findViewById(R.id.delete_btn); ac_btn = (Button) findViewById(R.id.ac_btn); /** * 結果 */ mResultText = (EditText) findViewById(R.id.result_text); /** * 已經輸入的字符 */ existedText = mResultText.getText().toString(); } /** * 初始化事件 */ private void initEvent() { num0.setOnClickListener(this); num1.setOnClickListener(this); num2.setOnClickListener(this); num3.setOnClickListener(this); num4.setOnClickListener(this); num5.setOnClickListener(this); num6.setOnClickListener(this); num7.setOnClickListener(this); num8.setOnClickListener(this); num9.setOnClickListener(this); plus_btn.setOnClickListener(this); subtract_btn.setOnClickListener(this); multiply_btn.setOnClickListener(this); divide_btn.setOnClickListener(this); equal_btn.setOnClickListener(this); dot_btn.setOnClickListener(this); percent_btn.setOnClickListener(this); delete_btn.setOnClickListener(this); ac_btn.setOnClickListener(this); } /** * 點擊事件 * @param v 點擊的控件 */ @Override public void onClick(View v) { switch (v.getId()){ /** * 數字 */ case R.id.num_zero: existedText = isOverRange(existedText,"0"); break; case R.id.num_one: existedText = isOverRange(existedText,"1"); break; case R.id.num_two: existedText = isOverRange(existedText,"2"); break; case R.id.num_three: existedText = isOverRange(existedText,"3"); break; case R.id.num_four: existedText = isOverRange(existedText,"4"); break; case R.id.num_five: existedText = isOverRange(existedText,"5"); break; case R.id.num_six: existedText = isOverRange(existedText,"6"); break; case R.id.num_seven: existedText = isOverRange(existedText,"7"); break; case R.id.num_eight: existedText = isOverRange(existedText,"8"); break; case R.id.num_nine: existedText = isOverRange(existedText,"9"); break; /** * 運算符 */ case R.id.plus_btn: /** * 判斷已有的字符是否是科學計數 * 是 置零 * 否 進行下一步 * * 判斷表達式是否可以進行計算 * 是 先計算再添加字符 * 否 添加字符 * * 判斷計算後的字符是否是 error * 是 置零 * 否 添加運算符 */ if (!existedText.contains("e")) { if (judgeExpression()) { existedText = getResult(); if (existedText.equals("error")){ } else { existedText += "+"; } } else { if (isCounted) { isCounted = false; } if ((existedText.substring(existedText.length() - 1)).equals("-")) { existedText = existedText.replace("-", "+"); } else if ((existedText.substring(existedText.length() - 1)).equals("×")) { existedText = existedText.replace("×", "+"); } else if ((existedText.substring(existedText.length() - 1)).equals("÷")) { existedText = existedText.replace("÷", "+"); } else if (!(existedText.substring(existedText.length() - 1)).equals("+")) { existedText += "+"; } } } else { existedText = "0"; } break; case R.id.subtract_btn: if (!existedText.contains("e")) { if (judgeExpression()) { existedText = getResult(); if (existedText.equals("error")){ } else { existedText += "-"; } } else { if (isCounted) { isCounted = false; } if ((existedText.substring(existedText.length() - 1)).equals("+")) { // Log.d("Anonymous", "onClick: " + "進入減法方法"); existedText = existedText.replace("+", "-"); } else if ((existedText.substring(existedText.length() - 1)).equals("×")) { existedText = existedText.replace("×", "-"); } else if ((existedText.substring(existedText.length() - 1)).equals("÷")) { existedText = existedText.replace("÷", "-"); } else if (!(existedText.substring(existedText.length() - 1)).equals("-")) { existedText += "-"; } } } else { existedText = "0"; } break; case R.id.multiply_btn: if (!existedText.contains("e")) { if (judgeExpression()) { existedText = getResult(); if (existedText.equals("error")){ } else { existedText += "×"; } } else { if (isCounted) { isCounted = false; } if ((existedText.substring(existedText.length() - 1)).equals("+")) { existedText = existedText.replace("+", "×"); } else if ((existedText.substring(existedText.length() - 1)).equals("-")) { existedText = existedText.replace("-", "×"); } else if ((existedText.substring(existedText.length() - 1)).equals("÷")) { existedText = existedText.replace("÷", "×"); } else if (!(existedText.substring(existedText.length() - 1)).equals("×")) { existedText += "×"; } } } else { existedText = "0"; } break; case R.id.divide_btn: if (!existedText.contains("e")) { if (judgeExpression()) { existedText = getResult(); if (existedText.equals("error")){ } else { existedText += "÷"; } } else { if (isCounted) { isCounted = false; } if ((existedText.substring(existedText.length() - 1)).equals("+")) { existedText = existedText.replace("+", "÷"); } else if ((existedText.substring(existedText.length() - 1)).equals("-")) { existedText = existedText.replace("-", "÷"); } else if ((existedText.substring(existedText.length() - 1)).equals("×")) { existedText = existedText.replace("×", "÷"); } else if (!(existedText.substring(existedText.length() - 1)).equals("÷")) { existedText += "÷"; } } } else { existedText = "0"; } break; case R.id.equal_btn: existedText = getResult(); isCounted = true; break; /** * 其他 */ case R.id.dot_btn: /** * 判斷是否運算過 * 否 * 判斷是否有運算符,有 判斷運算符之後的數字,無 判斷整個數字 * 判斷數字是否過長,是則不能添加小數點,否則可以添加 * 判斷已經存在的數字裡是否有小數點 * 是 * 字符串置為 0. */ if (!isCounted){ if (existedText.contains("+") || existedText.contains("-") || existedText.contains("×") || existedText.contains("÷") ){ String param1 = null; String param2 = null; if (existedText.contains("+")) { param1 = existedText.substring(0, existedText.indexOf("+")); param2 = existedText.substring(existedText.indexOf("+") + 1); } else if (existedText.contains("-")) { param1 = existedText.substring(0, existedText.indexOf("-")); param2 = existedText.substring(existedText.indexOf("-") + 1); } else if (existedText.contains("×")) { param1 = existedText.substring(0, existedText.indexOf("×")); param2 = existedText.substring(existedText.indexOf("×") + 1); } else if (existedText.contains("÷")) { param1 = existedText.substring(0, existedText.indexOf("÷")); param2 = existedText.substring(existedText.indexOf("÷") + 1); } Log.d("Anonymous param1",param1); Log.d("Anonymous param2",param2); boolean isContainedDot = param2.contains("."); if (param2.length() >= 9){ } else if (!isContainedDot){ if (param2.equals("")){ existedText += "0."; } else { existedText += "."; } } else { return; } } else { boolean isContainedDot = existedText.contains("."); if (existedText.length() >= 9){ } else if (!isContainedDot){ existedText += "."; } else { return; } } isCounted = false; } else { existedText = "0."; isCounted = false; } break; case R.id.percent_btn: /** * 判斷數字是否有運算符 * 是 不做任何操作 * 否 進行下一步 * * 判斷數字是否是 0 * 是 不做任何操作 * 否 進行除百 * * 將字符串轉換成double類型,進行運算後,再轉換成String型 */ if (existedText.equals("error")){ } else { getCondition(); if (startWithOperator || startWithSubtract || noStartWithOperator) { } else { if (existedText.equals("0")) { return; } else { double temp = Double.parseDouble(existedText); temp = temp / 100; existedText = String.valueOf(temp); } } } break; case R.id.delete_btn: /** * 字符串長度大於 0 時才截取字符串 * 如果長度為 1,則直接把字符串設置為 0 */ if (existedText.equals("error")){ existedText = "0"; } else if (existedText.length() > 0){ if (existedText.length() == 1) { existedText = "0"; } else { existedText = existedText.substring(0,existedText.length()-1); } } break; case R.id.ac_btn: existedText = "0"; break; } /** * 設置顯示 */ mResultText.setText(existedText); } /** * 進行運算,得到結果 * @return 返回結果 */ private String getResult() { /** * 結果 */ String tempResult = null; /** * 兩個String類型的參數 */ String param1 = null; String param2 = null; /** * 轉換後的兩個double類型的參數 */ double arg1 = 0; double arg2 = 0; double result = 0; getCondition(); /** * 如果有運算符,則進行運算 * 沒有運算符,則把已經存在的數據再傳出去 */ if ( startWithOperator || noStartWithOperator || startWithSubtract) { if (existedText.contains("+")) { /** * 先獲取兩個參數 */ param1 = existedText.substring(0, existedText.indexOf("+")); param2 = existedText.substring(existedText.indexOf("+") + 1); /** * 如果第二個參數為空,則還是顯示當前字符 */ if (param2.equals("")){ tempResult = existedText; } else { /** * 轉換String為Double * 計算後再轉換成String類型 * 進行正則表達式處理 */ arg1 = Double.parseDouble(param1); arg2 = Double.parseDouble(param2); result = arg1 + arg2; tempResult = String.format("%f", result); tempResult = subZeroAndDot(tempResult); } } else if (existedText.contains("×")) { param1 = existedText.substring(0, existedText.indexOf("×")); param2 = existedText.substring(existedText.indexOf("×") + 1); if (param2.equals("")){ tempResult = existedText; } else { arg1 = Double.parseDouble(param1); arg2 = Double.parseDouble(param2); result = arg1 * arg2; tempResult = String.format("%f", result); tempResult = subZeroAndDot(tempResult); } } else if (existedText.contains("÷")) { param1 = existedText.substring(0, existedText.indexOf("÷")); param2 = existedText.substring(existedText.indexOf("÷") + 1); if (param2.equals("0")){ tempResult = "error"; } else if (param2.equals("")){ tempResult = existedText; } else { arg1 = Double.parseDouble(param1); arg2 = Double.parseDouble(param2); result = arg1 / arg2; tempResult = String.format("%f", result); tempResult = subZeroAndDot(tempResult); } } else if (existedText.contains("-")) { /** * 這裡是以最後一個 - 號為分隔去取出兩個參數 * 進到這個方法,必須滿足有運算公式 * 而又避免了第一個參數是負數的情況 */ param1 = existedText.substring(0, existedText.lastIndexOf("-")); param2 = existedText.substring(existedText.lastIndexOf("-") + 1); if (param2.equals("")){ tempResult = existedText; } else { arg1 = Double.parseDouble(param1); arg2 = Double.parseDouble(param2); result = arg1 - arg2; tempResult = String.format("%f", result); tempResult = subZeroAndDot(tempResult); } } /** * 如果數據長度大於等於10位,進行科學計數 * * 如果有小數點,再判斷小數點前是否有十個數字,有則進行科學計數 */ if (tempResult.length() >= 10) { tempResult = String.format("%e", Double.parseDouble(tempResult)); } else if (tempResult.contains(".")) { if (tempResult.substring(0, tempResult.indexOf(".")).length() >= 10) { tempResult = String.format("%e", Double.parseDouble(tempResult)); } } } else { tempResult = existedText; } return tempResult; } /** * 先判斷是否按過等於號 * 是 按數字則顯示當前數字 * 否 在已有的表達式後添加字符 * * 判斷數字是否就是一個 0 * 是 把字符串設置為空字符串。 * 1、打開界面沒有運算過的時候,AC鍵歸零或刪除完歸零的時候,會顯示一個 0 * 2、當數字是 0 的時候,設置成空字符串,再按 0 ,數字會還是 0,不然可以按出 000 這種數字 * 否 添加按下的鍵的字符 * * 判斷數字是否包含小數點 * 是 數字不能超過十位 * 否 數字不能超過九位 * * 進行上面的判斷後,再判斷數字是否超過長度限制 * 超過不做任何操作 * 沒超過可以再添數字 */ private String isOverRange(String existedText, String s) { /** * 判斷是否計算過 */ if (!isCounted){ /** * 判斷是否是科學計數 * 是 文本置零 */ if (existedText.contains("e")){ existedText = "0"; } /** * 判斷是否只有一個 0 * 是 文本清空 */ if (existedText.equals("0")){ existedText = ""; } /** * 判斷是否有運算符 * 是 判斷第二個數字 * 否 判斷整個字符串 */ if (existedText.contains("+") || existedText.contains("-") || existedText.contains("×") || existedText.contains("÷")){ /** * 包括運算符時 兩個數字 判斷第二個數字 * 兩個參數 */ String param2 = null; if (existedText.contains("+")){ param2 = existedText.substring(existedText.indexOf("+")+1); } else if (existedText.contains("-")){ param2 = existedText.substring(existedText.indexOf("-")+1); } else if (existedText.contains("×")){ param2 = existedText.substring(existedText.indexOf("×")+1); } else if (existedText.contains("÷")){ param2 = existedText.substring(existedText.indexOf("÷")+1); } // Log.d("Anonymous param1",param1); // Log.d("Anonymous param2",param2); if (existedText.substring(existedText.length()-1).equals("+") || existedText.substring(existedText.length()-1).equals("-") || existedText.substring(existedText.length()-1).equals("×") || existedText.substring(existedText.length()-1).equals("÷")){ existedText += s; } else { if (param2.contains(".")){ if (param2.length() >= 10){ } else { existedText += s; } } else { if (param2.length() >= 9){ } else { existedText += s; } } } } else { /** * 不包括運算符時 一個數字 */ if (existedText.contains(".")){ if (existedText.length() >= 10){ } else { existedText += s; } } else { if (existedText.length() >= 9){ } else { existedText += s; } } } isCounted = false; } else { existedText = s; isCounted = false; } return existedText; } /** * 使用java正則表達式去掉多余的.與0 * @param s 傳入的字符串 * @return 修改之後的字符串 */ public static String subZeroAndDot(String s){ if(s.indexOf(".") > 0){ s = s.replaceAll("0+?$", "");//去掉多余的0 s = s.replaceAll("[.]$", "");//如最後一位是.則去掉 } return s; } /** * 判斷表達式 * * 為了按等號是否進行運算 * 以及出現兩個運算符(第一個參數如果為負數的符號不計)先進行運算再添加運算符 */ private boolean judgeExpression() { getCondition(); String tempParam2 = null; if ( startWithOperator || noStartWithOperator || startWithSubtract) { if (existedText.contains("+")) { /** * 先獲取第二個參數 */ tempParam2 = existedText.substring(existedText.indexOf("+") + 1); /** * 如果第二個參數為空,表達式不成立 */ if (tempParam2.equals("")) { return false; } else { return true; } } else if (existedText.contains("×")) { tempParam2 = existedText.substring(existedText.indexOf("×") + 1); if (tempParam2.equals("")) { return false; } else { return true; } } else if (existedText.contains("÷")) { tempParam2 = existedText.substring(existedText.indexOf("÷") + 1); if (tempParam2.equals("")) { return false; } else { return true; } } else if (existedText.contains("-")) { /** * 這裡是以最後一個 - 號為分隔去取出兩個參數 * 進到這個方法,必須滿足有運算公式 * 而又避免了第一個參數是負數的情況 */ tempParam2 = existedText.substring(existedText.lastIndexOf("-") + 1); if (tempParam2.equals("")) { return false; } else { return true; } } } return false; } /** * 取得判斷條件 */ private void getCondition() { /** * 以負號開頭,且運算符不是是減號 * 例如:-21×2 */ startWithOperator = existedText.startsWith("-") && ( existedText.contains("+") || existedText.contains("×") || existedText.contains("÷") ); /** * 以負號開頭,且運算符是減號 * 例如:-21-2 */ startWithSubtract = existedText.startsWith("-") && ( existedText.lastIndexOf("-") != 0 ); /** * 不以負號開頭,且包含運算符 * 例如:21-2 */ noStartWithOperator = !existedText.startsWith("-") && ( existedText.contains("+") || existedText.contains("-") || existedText.contains("×") || existedText.contains("÷")); } }
UI組件之ImageView及其子類(一)ImageView顯示圖片 ImageView家族的繼承關系如圖: ImageView繼承自View組件,它的主要功能室顯示圖
Android開發之基於AndroidStudio環境搭建和工程創建,androidstudio搭建斷斷續續的學習安卓也有一段時間了。因為之前是搞iOS開發的, 之前有關
Android jni開發中的常見錯誤,androidjni錯誤1:java.lang.UnsatisfiedLinkError: Native method not f
Android項目從Eclipse增加支持Android Studio 使用Eclipse開發Android已經有些年頭了,然而Android Studio(後面簡稱