Android簡易計算器(四)—— 完整邏輯程式碼
最近在學安卓的相關知識,第一個demo做了一個簡易計算器,功能仿手機上自帶的計算器,沒有加括號,簡單的四則運算,支援長表示式運算。此篇貼出本次簡易計算器完整邏輯程式碼。
程式碼如下:
package com.example.zwkkkk1.caculator1;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;
import java.math.BigDecimal;
import java.util.Stack;
import java.util.regex.Pattern;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private static String TAG = "CACULATOR";
TextView txt_result, txt_edit;
boolean isOperateDown = false;//運算子是否已經按過一次,預設沒有按過 false
boolean isDotDown = false ;//. 是否已經按過一次,預設沒有按過 false
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
txt_edit = (TextView)findViewById(R.id.txt_edit);
txt_result = (TextView)findViewById(R.id.txt_result);
findViewById(R.id.btn_0).setOnClickListener(this );
findViewById(R.id.btn_1).setOnClickListener(this);
findViewById(R.id.btn_2).setOnClickListener(this);
findViewById(R.id.btn_3).setOnClickListener(this);
findViewById(R.id.btn_4).setOnClickListener(this);
findViewById(R.id.btn_5).setOnClickListener(this);
findViewById(R.id.btn_6).setOnClickListener(this);
findViewById(R.id.btn_7).setOnClickListener(this);
findViewById(R.id.btn_8).setOnClickListener(this);
findViewById(R.id.btn_9).setOnClickListener(this);
findViewById(R.id.btn_divide).setOnClickListener(this);
findViewById(R.id.btn_multi).setOnClickListener(this);
findViewById(R.id.btn_plus).setOnClickListener(this);
findViewById(R.id.btn_sub).setOnClickListener(this);
findViewById(R.id.btn_equal).setOnClickListener(this);
findViewById(R.id.btn_clear).setOnClickListener(this);
findViewById(R.id.btn_back).setOnClickListener(this);
findViewById(R.id.btn_equal).setOnClickListener(this);
findViewById(R.id.btn_dot).setOnClickListener(this);
}
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_0:
num_down("0");break;
case R.id.btn_1:
num_down("1");break;
case R.id.btn_2:
num_down("2");break;
case R.id.btn_3:
num_down("3");break;
case R.id.btn_4:
num_down("4");break;
case R.id.btn_5:
num_down("5");break;
case R.id.btn_6:
num_down("6");break;
case R.id.btn_7:
num_down("7");break;
case R.id.btn_8:
num_down("8");break;
case R.id.btn_9:
num_down("9");break;
case R.id.btn_plus:
operator_down("+");break;
case R.id.btn_sub:
operator_down("-");break;
case R.id.btn_divide:
operator_down("÷");break;
case R.id.btn_multi:
operator_down("×");break;
case R.id.btn_clear:
isDotDown = false;
isOperateDown = false;
txt_edit.setText("0");
txt_result.setText("");
break;
case R.id.btn_back: {
String strEdit = txt_edit.getText().toString();
int length = strEdit.length();
if (Pattern.matches("^=[0-9].*", strEdit)) {
txt_edit.setText("0");
txt_result.setText("");
} else {
if (length > 0) {
String word = strEdit.substring(length - 1, length);
if(word.equals("."))
isDotDown = false;
if(word.equals("+") || word.equals("-") || word.equals("×") || word.equals("÷"))
isOperateDown = false;
txt_edit.setText(strEdit.substring(0, length - 1));
}
}
break;
}
case R.id.btn_dot: {
String strEdit = txt_edit.getText().toString();
if (!isDotDown) {
isDotDown = true;
if(Pattern.matches("^=[0-9].*", strEdit))
strEdit = "0";
txt_edit.setText(strEdit + ".");
}
break;
}
case R.id.btn_equal:
equal();break;
}
}
//按下數字函式
private void num_down(String num) {
String strEdit = txt_edit.getText().toString();
isOperateDown = false;
if (strEdit.equals("0") || Pattern.matches("^=[0-9].*", strEdit)) {
txt_edit.setText(num);
txt_result.setText("");
} else {
txt_edit.setText(strEdit + num);
}
}
// 按下運算子函式
private void operator_down(String operator) {
if(!isOperateDown) {
String strEdit = txt_edit.getText().toString();
isOperateDown = true;
isDotDown = false;
if(Pattern.matches("^=[0-9].*", strEdit))
strEdit = strEdit.substring(1, strEdit.length());
txt_edit.setText(strEdit + operator);
}
}
private void equal() {
String strEdit = txt_edit.getText().toString();
int length = strEdit.length();
if(!Pattern.matches("^=[0-9].*", strEdit))
{
txt_result.setText(strEdit);
if(Pattern.matches(".*[\\+\\-\\×\\÷\\.]$", strEdit)) {
strEdit = strEdit.substring(0, length - 1);
}
String postfixExp = getPostfixExp(strEdit);
txt_edit.setText("=" + calPostfix(postfixExp));
}
}
//將中綴表示式轉換為字尾表示式
private String getPostfixExp(String str) {
String postfix = "";
String numString = ""; //因數字 不止一位需要String儲存
Stack numStack = new Stack();
Stack opStack = new Stack();
for(int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if(Character.isDigit(ch) || ch == '.') { //判定ch 是否是數字 或者是 .
numString += String.valueOf(ch); //將數字和 .放入numString,等待下一個運算子
} else { //ch為運算子時
if(numString.length() > 0) {
numStack.push(numString);//將此運算子前數字壓入數字棧
numString = ""; //壓入棧後,初始化 numString
}
opPush(opStack, numStack, ch);
}
}
//最後判定numString是否為空,因為最後一個可能是數字,沒有運算子進行判定
if(numString.length() > 0)
numStack.push(numString);
//檢測完後,將運算子棧中轉入到數字棧中
while(!opStack.empty()) {
numStack.push(opStack.pop());
}
//將數字棧打印出來得到字尾表示式
//此處需要將字串逆序,才得到字尾表示式,但是有小數點的存在,不能直接用 reverse 的逆序函式
//通過兩個棧的先進後出特點,得到棧的逆序
while(!numStack.empty()) {
opStack.push(numStack.pop());
}
while(!opStack.empty()) {
postfix = postfix + String.valueOf(opStack.pop()) + " ";
}
return postfix;
}
//計算字尾表示式
private String calPostfix(String str) {
String result = "";
Stack numStack = new Stack();
for(int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if(ch == ' ') {
//運算子時
if(result.length() > 0 && (result.equals("+") || result.equals("-") || result.equals("×") || result.equals("÷")))
{
double num = 0;
double secondNum = Double.parseDouble(String.valueOf(numStack.pop()));
double firstNum = Double.parseDouble(String.valueOf(numStack.pop()));
switch (result) {
case "+":
num = firstNum + secondNum;break;
case "-":
num = firstNum - secondNum;break;
case "×":
num = firstNum * secondNum;break;
case "÷":
num = firstNum / secondNum;break;
}
numStack.push(num);
}
else if(result.length() > 0) {
numStack.push(result);
}
result = "";
} else {
result += String.valueOf(ch);
}
}
return BigDecimal.valueOf(Double.valueOf(String.valueOf(numStack.pop()))).stripTrailingZeros().toPlainString();
}
//獲取運算子權重
private int getOpWeight(char ch) {
// + - 權重為1
if(ch == '+' || ch == '-') return 1;
//× ÷ 權重為2
if(ch == '×' || ch == '÷') return 4;
return -1;
}
//將運算子壓入棧
private void opPush(Stack opStack, Stack numStack, char ch) {
if(canOpPush(opStack, ch)) { //判定能否將運算子壓入棧內
opStack.push(ch); //true則壓入棧內
} else { //false(即 待壓入運算子優先順序 <= 棧頂運算子優先順序)
//將棧頂運算子取出壓入數字棧
numStack.push(String.valueOf(opStack.pop()));
//此處需要遞迴判定,彈出所有優先順序 >= 該運算子的棧頂元素
opPush(opStack, numStack, ch);
}
}
//判定運算子能否壓入運算子棧
private Boolean canOpPush(Stack opStack, char ch) {
//當運算子棧為空時,返回true;或當待壓入運算子權重大於棧頂權重,返回true
if(opStack.empty() || (getOpWeight(ch) > getOpWeight(String.valueOf(opStack.peek()).charAt(0))))
return true;
return false; //其他情況返回false
}
}
相關推薦
Android簡易計算器(四)—— 完整邏輯程式碼
最近在學安卓的相關知識,第一個demo做了一個簡易計算器,功能仿手機上自帶的計算器,沒有加括號,簡單的四則運算,支援長表示式運算。此篇貼出本次簡易計算器完整邏輯程式碼。 程式碼如下: package com.example.zwkkkk1.cacul
Android MVP系列(四)之完整MVC
今天這篇文章主要分為兩大部分: 一、為上一章的MVC賦予靈動的生命; 二、指出MVC的不足和引出MVP的優點; 題外話 可能有人會說,你寫個MVP,為啥用了前面三篇(Android MVP系列(一)、Android MVP系列(二)之MVC結構、Andr
Android Camera2 拍照(四)——對焦模式
ask als size com ontouch eating fault tdi release 原文:Android Camera2 拍照(四)——對焦模式 本
Android SurfaceFlinger服務(四) ----- 消息機制MessageQueue
events on() inpu str lB 取消 onf CA andro SurfaceFlinger有著自己的消息隊列MessageQueue,用來處理顯示相關的消息,比如Vsync消息。 相關文件: frameworks/native/services/surf
Android 開發:(四)Button圓角實現
本節學習button的圓角實現: 利用上節登入button示例: 1.效果對比: <Button android:layout_width="match_parent" android:layout_height="45dp
智慧語音計算器(四)
最後說訊飛的語音引擎部分,這部分的實現邏輯可以參考官方給的demo,一步一步來就行。 #ifndef CALCULATORASR_H #define CALCULATORASR_H #include <stdio.h> #include <string.h> #include
Android入門筆記(四)
四、fragment argument 和 頁面資料更新 4.1 為什麼要使用 fragment argument 當 fragment 和 activity 間的資料進行傳遞時,如果只是簡單的使用 intent 的 extra 來進行傳遞資訊,不僅破
Ocelot簡易教程(四)之請求聚合以及服務發現
上篇文章給大家講解了Ocelot的一些特性並對路由進行了詳細的介紹,今天呢就大家一起來學習下Ocelot的請求聚合以及服務發現功能。希望能對大家有所幫助。 請求聚合 Ocelot允許你宣告聚合路由,這樣你可以把多個正常的ReRoutes打包並對映到一個物件來對客戶端的請求進行響應。比如,你請求訂單資訊,訂單
Android進階(四):Activity啟動過程(最詳細&最簡單)
1.前言 最近一直在看 《Android進階解密》 的一本書,這本書編寫邏輯、流程都非常好,而且很容易看懂,非常推薦大家去看看(沒有收廣告費,單純覺得作者寫的很好)。 上一篇簡單的介紹了Android進階(三):Application啟動過程(最詳細&最簡單)
Android開發筆記(四)字串格式化
字串的格式化 博主原來是搞C的,C裡面有sprintf來格式化字串,後來轉到java變傻了,拼接String只會用n個“+”,要麼就是用StringBuilder的append方法,但要是遇上把數字格式化的情況(比如左補0等等),就只能傻乎乎的if else判斷該補幾個0。
床頭筆記之Android開發學習(四)
新建HelloWorld工程專案目錄說明: 工程目錄: 按著下圖順序講解 HelloWorld: 專案名 src: 自己編寫的程式存放處 gen: 系統自動生成的檔案R.java(和res資原始檔關聯,為其子檔案drawable下每個圖片及values下的鍵值
Android產品研發(四)-->減小Apk大小
隨著移動技術的深入發展,各種炫酷效果的更新,在我們追求UI與UE的同時一個不如忽視的問題逐漸暴露出來,那就是apk檔案越來越大,可能有的童鞋會說現在都是wifi環境,apk檔案增大幾M不是什麼大不了的問題,這其實也是有一定道理的,但是作為開發人員的我們這絕不
Android Firebase接入(四)-- AdMob廣告
AdMob廣告可以幫助app實現盈利。一、配置Android應用並下載google-service.json檔案:二、新增AdMob依賴:implementation 'com.google.firebase:firebase-ads:15.0.0'初始化AdMob,推薦在A
Android Multimedia實戰(四)MediaProjection實現截圖,與MediaMuxer實現錄屏為MP4,Gif格式
MediaProjection可以用來捕捉螢幕,具體來說可以擷取當前螢幕和錄製螢幕視訊 (5.0以上) 先總結下系統是如何實現組合鍵截圖的: 都應該知道Android原始碼中對按鍵的捕獲位於檔案PhoneWindowManager.java中 當滿足按鍵
Android動畫篇(四):最終效果篇CircleProgressSuperBar
前言 今天終於有時間把最後的成果分享給大家了,為了提高一下部落格的逼格,我也找了一個專門做原型、導圖的線上網站:processon(www.processon.com),這個工具真的很棒,也很方便,這裡給他點個贊。 CircleProgressSuperBa
我所理解的Android模組化(四)——常見問題和注意事項
關於Android模組化,前面已經寫了三篇文章,沒有了解的大家可以先去看一下,附上鍊接地址: 下面主要來說一下Android模組化過程中的常見問題和注意事項: 注意事項 記得在一篇技術部落格中看到微信Tinker的開發人員說過一句話
Android原始碼編譯(四)系統原始碼目錄
Android 8.0之後原始碼目錄有所改變 Android平臺四層架構對應原始碼中的目錄: 第一層:應用程式層(applications)對應根目錄下packages/apps 第二層:應用程式框架層(application framework)對應根目錄下的f
Android學習筆記(四)--RecyclerView擴充套件下拉重新整理與左滑刪除
今天在使用QQ的時候就想到製作一個訊息列表的類似效果,可以實現下拉重新整理和左滑刪除效果,於是就抽空試了試。先上效果圖。 這是正在重新整理的時候。然後就會增添一個item(那個重新整理的圈是會轉的然後還可以變顏色我不會截動圖)。見下圖。 Recycl
Android學習筆記(四)之碎片化Fragment實現仿人人客戶端的側邊欄
其實一種好的UI佈局,可以使使用者感到更加的親切與方便。最近非常流行的莫過於側邊欄了,其實我也做過很多側邊欄的應用,但是那些側邊欄的使用我都不是很滿意,現在重新整理,重新寫了一個相對來說我比較滿意的側邊欄,其中運用的就是android3.0版本之後新加的Fragme
Android學習路線(四)構建一個簡單的UI
Android應用的圖形化使用者介面的構建使用的是View 和 物件的層次巢狀。 View 物件通常是UI部件,例如 buttons 或者 text fields ,而 是用來定義它的子佈局如何排布的容器,它通常是不可見的,例如一個網格或者一個垂直的列表。 And