編輯:關於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顯示圖片
UI組件之ImageView及其子類(一)ImageView顯示圖片 ImageView家族的繼承關系如圖: ImageView繼承自View組件,它的主要功能室顯示圖
Android開發之基於AndroidStudio環境搭建和工程創建,androidstudio搭建
Android開發之基於AndroidStudio環境搭建和工程創建,androidstudio搭建斷斷續續的學習安卓也有一段時間了。因為之前是搞iOS開發的, 之前有關
Android jni開發中的常見錯誤,androidjni
Android jni開發中的常見錯誤,androidjni錯誤1:java.lang.UnsatisfiedLinkError: Native method not f
Android項目從Eclipse增加支持Android Studio
Android項目從Eclipse增加支持Android Studio 使用Eclipse開發Android已經有些年頭了,然而Android Studio(後面簡稱