From 00ae62ce9d79650a7a5bb99241c79163793379db Mon Sep 17 00:00:00 2001 From: LiangXiao Date: Sat, 21 Dec 2019 22:52:07 +0800 Subject: [PATCH] finish! --- .gitignore | 14 + .idea/codeStyles/Project.xml | 116 ++++++++ .idea/gradle.xml | 16 ++ .idea/misc.xml | 9 + .idea/runConfigurations.xml | 12 + app/.gitignore | 1 + app/build.gradle | 28 ++ app/proguard-rules.pro | 21 ++ .../mycalculator/ExampleInstrumentedTest.java | 27 ++ app/src/main/AndroidManifest.xml | 21 ++ .../wang/xice/mycalculator/Calculator.java | 258 ++++++++++++++++++ .../wang/xice/mycalculator/MainActivity.java | 177 ++++++++++++ .../drawable-v24/ic_launcher_foreground.xml | 34 +++ .../drawable/caculator_button_background.xml | 5 + .../res/drawable/caculator_button_normal.xml | 6 + .../res/drawable/ic_launcher_background.xml | 170 ++++++++++++ .../main/res/drawable/keyboard_background.xml | 6 + app/src/main/res/drawable/keyboard_normal.xml | 6 + app/src/main/res/layout/activity_main.xml | 58 ++++ app/src/main/res/layout/keyboard.xml | 188 +++++++++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 0 -> 4905 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 0 -> 2783 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 0 -> 6895 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 0 -> 10413 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 0 -> 15132 bytes app/src/main/res/values/colors.xml | 13 + app/src/main/res/values/dimens.xml | 7 + app/src/main/res/values/strings.xml | 3 + app/src/main/res/values/styles.xml | 11 + .../xice/mycalculator/CalculatorUnitTest.java | 20 ++ .../xice/mycalculator/ExampleUnitTest.java | 17 ++ build.gradle | 27 ++ gradle.properties | 20 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 6 + gradlew | 172 ++++++++++++ gradlew.bat | 84 ++++++ settings.gradle | 2 + 45 files changed, 1565 insertions(+) create mode 100644 .gitignore create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/gradle.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/wang/xice/mycalculator/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/wang/xice/mycalculator/Calculator.java create mode 100644 app/src/main/java/wang/xice/mycalculator/MainActivity.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/caculator_button_background.xml create mode 100644 app/src/main/res/drawable/caculator_button_normal.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/keyboard_background.xml create mode 100644 app/src/main/res/drawable/keyboard_normal.xml create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/keyboard.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/wang/xice/mycalculator/CalculatorUnitTest.java create mode 100644 app/src/test/java/wang/xice/mycalculator/ExampleUnitTest.java create mode 100644 build.gradle create mode 100644 gradle.properties create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100644 gradlew create mode 100644 gradlew.bat create mode 100644 settings.gradle diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..603b140 --- /dev/null +++ b/.gitignore @@ -0,0 +1,14 @@ +*.iml +.gradle +/local.properties +/.idea/caches +/.idea/libraries +/.idea/modules.xml +/.idea/workspace.xml +/.idea/navEditor.xml +/.idea/assetWizardSettings.xml +.DS_Store +/build +/captures +.externalNativeBuild +.cxx diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..681f41a --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,116 @@ + + + + + + + +
+ + + + xmlns:android + + ^$ + + + +
+
+ + + + xmlns:.* + + ^$ + + + BY_NAME + +
+
+ + + + .*:id + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + .*:name + + http://schemas.android.com/apk/res/android + + + +
+
+ + + + name + + ^$ + + + +
+
+ + + + style + + ^$ + + + +
+
+ + + + .* + + ^$ + + + BY_NAME + +
+
+ + + + .* + + http://schemas.android.com/apk/res/android + + + ANDROID_ATTRIBUTE_ORDER + +
+
+ + + + .* + + .* + + + BY_NAME + +
+
+
+
+
+
\ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..d291b3d --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..37a7509 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..70e852d --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,28 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 29 + defaultConfig { + applicationId "wang.xice.mycalculator" + minSdkVersion 16 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/app/src/androidTest/java/wang/xice/mycalculator/ExampleInstrumentedTest.java b/app/src/androidTest/java/wang/xice/mycalculator/ExampleInstrumentedTest.java new file mode 100644 index 0000000..6b83599 --- /dev/null +++ b/app/src/androidTest/java/wang/xice/mycalculator/ExampleInstrumentedTest.java @@ -0,0 +1,27 @@ +package wang.xice.mycalculator; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + + assertEquals("wang.xice.mycalculator", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fd93ee8 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/wang/xice/mycalculator/Calculator.java b/app/src/main/java/wang/xice/mycalculator/Calculator.java new file mode 100644 index 0000000..3e398af --- /dev/null +++ b/app/src/main/java/wang/xice/mycalculator/Calculator.java @@ -0,0 +1,258 @@ +package wang.xice.mycalculator; + +import java.util.ArrayList; +import java.util.Stack; + +/** + * 计算输入的表达式 + */ +public class Calculator { + + public static String calculate(String downStr) throws Exception { + ArrayList inOrderList = getStringList(downStr); + ArrayList postOrderList = getPostOrderList(inOrderList); + double result = calPostOrderList(postOrderList); + if (result == Math.floor(result)) { + return (long) result + ""; + } + return result + ""; + } + + /** + * 将字符串放入栈中 --- 中序表达式 + * 按照 数字 符号 这种中序的顺序存入栈中 + * + * @return ArrayList 中缀表达式 + */ + private static ArrayList getStringList(String string) { + + ArrayList arrayList = new ArrayList<>(); + String num = ""; + String str = ""; + + for (int i = 0; i < string.length(); i++) { + + if ((Character.isDigit(string.charAt(i)) + || string.charAt(i) == '.' + || string.charAt(i) == 'e' + || string.charAt(i) == 'π')) { + // 当前的字符串是否是数字或者是点号 + num += string.charAt(i); + }else if(Character.isLetter(string.charAt(i))){ + str += string.charAt(i); + } else {// 当前输入的字符不是数字或者点号 + + if (i == 0 && isSubOperator(string.charAt(i) + "")) { + // 当最后一次计算结果为负数时候, + //为输入的String第一位添加0 保证再次做减法的正确性 + arrayList.add("0"); + } + if (!str.equals("")) { + arrayList.add(str); + } + if (!num.equals("")) { + arrayList.add(num); + } + arrayList.add(string.charAt(i) + ""); + str = ""; + num = ""; + } + } + + if (!str.equals("")) {// 添加最后一个一元运算符 + arrayList.add(str); + } + if (!num.equals("")) {// 添加最后一个数字 + arrayList.add(num); + } + + return arrayList; + } + + /** + * 把中缀表达式转化成后缀表达式 + * + * @param inOrderList ArrayList 中缀表达式 + * @return ArrayList 后缀表达式 + */ + private static ArrayList getPostOrderList(ArrayList inOrderList) { + + ArrayList postOrderList = new ArrayList<>(); + Stack operatorStack = new Stack<>(); + + for (int i = 0; i < inOrderList.size(); i++) { + + String current = inOrderList.get(i); + if (current.equals("(")){// 如果是左括号 + operatorStack.push(current); //直接入栈 + } + else if (current.equals(")")){ //如果是右括号 + while (!operatorStack.isEmpty() && !operatorStack.peek().equals("(")){ //将栈中的运算符全入栈 知道找到左括号 + postOrderList.add(operatorStack.pop()); + } + if (!operatorStack.isEmpty()) operatorStack.pop(); // 并将左括号出栈 + }else if (isOperator(current)) {// 如果是运算符 + while (!operatorStack.isEmpty() && compareLevel(operatorStack.peek(), current)) { // 判断优先级 进行入栈 + postOrderList.add(operatorStack.pop()); + } + operatorStack.push(current); + } else {// 如果不是运算符, 是数字或者是点号 + postOrderList.add(inOrderList.get(i)); + } + } + + while (!operatorStack.isEmpty()) { + postOrderList.add(operatorStack.pop()); + } + + return postOrderList; + } + + /** + * 比较运算符之间的优先级 + * 比较当前运算符与运算符栈顶的运算符的优先级 + * 若栈顶元算符优先级大于当前元算符则出栈,把运算符栈顶元素放入 + * 后缀表达式栈中 + * --- + * 若栈顶元算符优先级大于或等于当前元算符返回true + * + * @param stackTop String 栈顶运算符 + * @param current String 当前运算符 + * @return boolean 是否优先 + */ + private static boolean compareLevel(String stackTop, String current) { + if (isOperator(stackTop) && !isSubOperator(stackTop)){ // sin cos啥的 + return true; + } + if (isOperator(current) && !isSubOperator(current)){ + return false; + } + if (stackTop.equals("*") && (current.equals("*") + || current.equals("/") + || current.equals("+") + || current.equals("-"))) { + return true; + } + + if (stackTop.equals("/") && (current.equals("*") + || current.equals("/") + || current.equals("+") + || current.equals("-"))) { + return true; + } + + if (stackTop.equals("+") && (current.equals("+") + || current.equals("-"))) { + return true; + } + + if (stackTop.equals("-") && (current.equals("-") + || current.equals("+"))) { + return true; + } + + return false; + } + + /** + * 判断是否是运算符 + * + * @return boolean 是否是运算符 + */ + private static boolean isOperator(String string) { + return string.equals("+") + || string.equals("-") + || string.equals("*") + || string.equals("/") + || string.equals("sin") + || string.equals("cos") + || string.equals("log") + || string.equals("tan"); + } + /** + * 判断运算符前面是否应该有数 + * + * @return boolean 是否是二元运算符 + * */ + private static boolean isSubOperator(String string) { + return string.equals("+") + || string.equals("-") + || string.equals("*") + || string.equals("/"); + } + + /** + * 将含有e π 的字符串转成对应的数 + * + * @return double 转化之后的数字 + * */ + private static double strToDouble(String s) { + switch (s){ + case "e": + return Math.E; + case "π": + return Math.PI; + default: + return Double.parseDouble(s); + } + } + + /** + * 计算后缀表达式 + * 如果是数字或者点号直接存入到堆栈中,遇到运算符则弹出栈顶的两个元素 + * 然后计算得到结果之后在存入栈中 + */ + private static double calPostOrderList(ArrayList postOrderList) throws Exception { + + Stack stack = new Stack<>(); + for (int i = 0; i < postOrderList.size(); i++) { + + String curStr = postOrderList.get(i); + if (isSubOperator(curStr)) {// 二元运算符 弹出栈顶的两个元素,然后进行计算,注意a是被操作数先弹出的a + double a = strToDouble(stack.pop()); + double b = strToDouble(stack.pop()); + double result = 0.0; + switch (curStr.charAt(0)) { + case '+': + result = b + a; + break; + case '-': + result = b - a; + break; + case '/': + if (a == 0) throw new Exception(); + result = b / a; + break; + case '*': + result = b * a; + break; + } + + stack.push(result + ""); + }else if (isOperator(curStr)){ // 一元运算符仅需要弹出一个元素进行计算 + double a = strToDouble(stack.pop()); + double result = 0.0; + switch (curStr) { + case "sin": + result = Math.sin(a); + break; + case "cos": + result = Math.cos(a); + break; + case "tan": + result = Math.tan(a); + break; + case "log": + result = Math.log(a); + break; + } + + stack.push(result + ""); + } else { + stack.push(curStr); + } + } + + return Double.parseDouble(stack.pop()); + } +} \ No newline at end of file diff --git a/app/src/main/java/wang/xice/mycalculator/MainActivity.java b/app/src/main/java/wang/xice/mycalculator/MainActivity.java new file mode 100644 index 0000000..30668da --- /dev/null +++ b/app/src/main/java/wang/xice/mycalculator/MainActivity.java @@ -0,0 +1,177 @@ +package wang.xice.mycalculator; + +import android.content.Context; +import android.os.Bundle; +import android.util.Log; +import android.view.View; +import android.view.WindowManager; +import android.view.animation.AlphaAnimation; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.TranslateAnimation; +import android.widget.Button; +import android.widget.EditText; +import android.widget.LinearLayout; + +import androidx.appcompat.app.AppCompatActivity; + +import java.util.ArrayList; + +public class MainActivity extends AppCompatActivity { + + + private static final String TAG = "MainActivity"; + private String downStr = ""; + private boolean last_input = false;// 上一次输入是否为等号 + + private ArrayList