目录
前言
运行结果:
运行截屏(p50e)
apk文件
源码文件
项目结构
总览
MainActivity.java
drawable
更改图标的方法:
layout
布局文件
竖屏:
横屏:
values
colors.xml
strings.xml
styles
浅色模式
深色模式
themes.xml
本文章以及之后文章的程序版本使用Android Studio 2022.3.1 Patch 1 版本编辑,使用语言为java,最低支持API 27 Android 8.1,构建工具版本如下:
先粘贴运行结果和源码文件和apk链接(实机演示,使用模拟器和华为P30和P50E均可执行)本图片为P50E运行截屏
屏幕大小不会导致布局变形,不放视频了,akp可以直接下载使用看一看
i道i的计算器1.0版本apk文件https://download.csdn.net/download/weixin_58196051/88393857
i道i的计算器1.0版本源码文件,注意Android Studio版本,(更低版本能打开,但没有虚拟目录)https://download.csdn.net/download/weixin_58196051/88393859
不要在意这个文件名为什么
这是1.0版本里面的编辑模式目录,主函数东西不多,大多都是重复的绑定而已,初学还是看看布局之类的。
这里只是一个记录,具体的建议打开源码看看
AndroidManifest.xml中都是自动生成的,这里只有一个窗口,也没新加注册,我们就不看了。
主函数,这里获取了activity_main.xml中的各种控件引用,并添加了一些监听器之类的常规操作,最后用栈做的方法,中缀表达式转后缀表达式那一套,虽然有近千行,但很多是重复的,注释多看看就没问题,稍微值得注意的就是对onSaveInstanceState方法的重写,保存了一些数据防止在旋转时遗失,然后再在onCreate中读取出来。
package com.example.calculatorddaa;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.HorizontalScrollView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Stack;
public class MainActivity extends AppCompatActivity {
//变量定义
EditText editText; //输入框:用于输入数字
TextView textView, textView_Now, textView_M; //文本框:显示计算过程,第二个显示当前结果,第三个个显示是否存在记忆。
HorizontalScrollView horizonLayout_Last, horizonLayout_Now;
Button button_rotate; // 按钮,旋转
Button[] number_buttons = new Button[10]; // 按钮:十个数字
Button button_add, button_sub, button_mul, button_div; // 按钮:加减乘除
Button button_point, button_equal_To, button_C, button_CE; // 按钮:小数点,等号,清空,退格
Button button_MR, button_Mup, button_Mdown, button_MC; // 按钮:读取记忆,记忆加,记忆减,记忆删除
//下面是横屏按钮
Button button_left_parenthesis, button_right_parenthesis;// 两个括号
Button button_e, button_pi;//两个特殊变量
Button button_reciprocal, button_square, button_cubic_power, button_n_power;// 倒数,二次方,三次方,n次方,
Button button_square_root, button_cube_root, button_n_root;// 平方根,立方根,n次根
Button button_inv;// 切换一元运算符的按钮(反函数)
Button button_ln, button_log;//ln,log
Button button_sin, button_cos, button_tan;// 三角函数们
String str_t_digit = "", str_t_equation = "", str_t_Now = ""; // 临时字符串,临时保存输入的数字和表达式和上次结果信息
Double digit_t = 0.0; // 临时变量
Integer parenthesis_n = 0; //未匹配的左括号数目,包含(,^(,三角函数(,ln(,log(
Boolean mark_inv = true;// 标记变量,标记inv的状态 true正,false反
ArrayList input_Double = new ArrayList<>(); // 储存用户输入的数字,用可变数组储存
ArrayList input_String = new ArrayList<>(); // 储存用户输入的运算符,用可变数组储存
ArrayList input_Boolean = new ArrayList<>(); // 储存用户输入是否是数字,用可变数组储存,
//直接入栈的字符串
ArrayList special_symbols = new ArrayList();
Double memory = 0.0; //记忆
NumberFormat nf = NumberFormat.getInstance();//Double转String
private final View.OnClickListener land_switch_onClickListener = new View.OnClickListener() {//横竖屏切换侦听器
@Override
public void onClick(View view) {//点击事件
try {
// 获取当前屏幕的方向
int currentOrientation = getResources().getConfiguration().orientation;
// 根据当前屏幕方向切换屏幕方向
if (currentOrientation == Configuration.ORIENTATION_LANDSCAPE) {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
}
} catch (Exception e) {
Log.e("land_switch", "error");
}
}
};
private final View.OnClickListener digit_onClickListener = new View.OnClickListener() {//数字侦听器,数字+小数点
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {
if (!str_t_equation.equals("") && str_t_equation.charAt(str_t_equation.length() - 1) == ')') {//前面是)不让输入数字
return;
} else if (button.getId() == R.id.button_0) {//如果点击了按钮:“0”
if (!(str_t_digit.equals("0"))) { //之前不是只有一个0,才添0,防止000这样情况出现
str_t_digit = str_t_digit + 0;
}
} else if (button.getId() == R.id.button_point) {
if (str_t_digit.contains(".")) { //判断字符串中是否已包含小数点,如果有,就什么也不做
return;
} else { //如果没有小数点
if (str_t_digit.equals("")) {//如果初时显示为空,就替换为"0."
str_t_digit = "0.";
} else {
str_t_digit = str_t_digit + ".";
}
}
} else { // 现在如果只有一个0,就删除0,
if (str_t_digit.equals("0")) {
str_t_digit = "";
}//接下来是1~9的按钮
if (button.getId() == R.id.button_1) {//如果点击了按钮:“1”
str_t_digit = str_t_digit + 1;//变量末尾,添加一个“1”
} else if (button.getId() == R.id.button_2) {//以此类推到9
str_t_digit = str_t_digit + 2;
} else if (button.getId() == R.id.button_3) {
str_t_digit = str_t_digit + 3;
} else if (button.getId() == R.id.button_4) {
str_t_digit = str_t_digit + 4;
} else if (button.getId() == R.id.button_5) {
str_t_digit = str_t_digit + 5;
} else if (button.getId() == R.id.button_6) {
str_t_digit = str_t_digit + 6;
} else if (button.getId() == R.id.button_7) {
str_t_digit = str_t_digit + 7;
} else if (button.getId() == R.id.button_8) {
str_t_digit = str_t_digit + 8;
} else if (button.getId() == R.id.button_9) {
str_t_digit = str_t_digit + 9;
} else {
Log.e("digit", "error");
return;
}
}
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
} catch (Exception e) {
Log.e("digit", "error");
}
}
};
private final View.OnClickListener operator_onClickListener = new View.OnClickListener() {//常用运算符侦听器,
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {
//+,-,*,÷逻辑一样,除零之类的运算时再判断
if (!str_t_digit.equals("")) {//有数字
digit_t = Double.parseDouble(str_t_digit);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_digit;
str_t_digit = ""; //删除之前的数字字符串
input_Boolean.add(true);// 入列了一个数字
// 根据按钮入列运算符------------------------------
} else {// 如果输入数字为空,多种情况,
// 前面什么都没有,但是textView_Now不空
if (str_t_equation.equals("") && !str_t_Now.equals("") && !str_t_Now.equals("错误")) {
//将textView_Now内容当数字进来
digit_t = Double.parseDouble(str_t_Now);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_Now;
input_Boolean.add(true);// 入列了一个数字
} else if (str_t_equation.equals("") || str_t_equation.charAt(str_t_equation.length() - 1) == '(') {
//前面什么都没有,或者是包含(的运算符(包含^(,三角函数,ln(,log(
if (button.getId() == R.id.button_sub) {//是减号正常加入
input_Double.add(0.0);// 入列了一个数字
str_t_equation += "0"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add("-"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "-"; // 运算符添加进表达式字符串
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
return;
} else {// 其他符号不理睬
Log.e("operator", "Blank in front");
return;
}
} else {//不是空,不是(,那就是运算符或者数字了
if ("+-*/".contains(String.valueOf(str_t_equation.charAt(str_t_equation.length() - 1)))) {//前面是+-*/之一
input_String.remove(input_String.size() - 1); // 删除这个运算符
input_Boolean.remove(input_Boolean.size() - 1);
str_t_equation = str_t_equation.substring(0, str_t_equation.length() - 1); //表达式中删除这个运算符
//根据运算符添加---------------------
}
// 是)和数字
// 根据按钮入列运算符------------------------------
}
}
if (button.getId() == R.id.button_add) {
input_String.add("+"); // 入列运算符
str_t_equation += "+"; // 运算符添加进表达式字符串
} else if (button.getId() == R.id.button_sub) {
input_String.add("-"); // 入列运算符
str_t_equation += "-"; // 运算符添加进表达式字符串
} else if (button.getId() == R.id.button_mul) {
input_String.add("*"); // 入列运算符
str_t_equation += "*"; // 运算符添加进表达式字符串
} else if (button.getId() == R.id.button_div) {
input_String.add("/"); // 入列运算符
str_t_equation += "/"; // 运算符添加进表达式字符串
} else {
Log.e("operator", "error");
return;
}
input_Boolean.add(false);// 入列了一个运算符
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
} catch (Exception e) {
Log.e("operator", "error");
}
}
};
private final View.OnClickListener memory_onClickListener = new View.OnClickListener() {//四个记忆功能和e,pi这两个特殊变量
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {
if (button.getId() == R.id.button_MC) {
memory = 0.0;// 清空记忆
textView_M.setText("");// 隐藏M标志
} else if (!str_t_equation.equals("") && str_t_equation.charAt(str_t_equation.length() - 1) == ')') {//前面是)不让输入数字,也不让MR,e,pi
//既然不让输入数字,就更不会出现M+,M-,但MC还能用
return;
} else if (button.getId() == R.id.button_MR) {
if (!textView_M.getText().equals("")) {// 不是空
str_t_digit = nf.format(memory); //替换
}
} else if (button.getId() == R.id.button_Mup) {
if (!str_t_digit.equals("")) {
memory += Double.parseDouble(str_t_digit);
if (memory != 0.0) {// 是空
textView_M.setText("M");// 显示M标志
} else {
textView_M.setText("");
}
}
} else if (button.getId() == R.id.button_Mdown) {
if (!str_t_digit.equals("")) {
memory -= Double.parseDouble(str_t_digit);
if (memory != 0.0) {// 是空
textView_M.setText("M");// 显示M标志
} else {
textView_M.setText("");
}
}
} else if (button.getId() == R.id.button_e) {
digit_t = Math.E;
str_t_digit = nf.format(digit_t);
; //替换
} else if (button.getId() == R.id.button_pi) {
digit_t = Math.PI;
str_t_digit = nf.format(digit_t);
; //替换
} else {
Log.e("memory", "error");
return;
}
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
} catch (Exception e) {
Log.e("memory", "error");
}
}
};
private final View.OnClickListener parenthesis_onClickListener = new View.OnClickListener() {//括号侦听器,
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {
if (button.getId() == R.id.button_left_parenthesis) {
//左括号可以出现在非数字的右边,前面什么都没有也行,如果是数字或者),前面添加一个乘号
if (!input_Boolean.isEmpty() && (input_Boolean.get(input_Boolean.size() - 1) || str_t_equation.charAt(str_t_equation.length() - 1) == ')')) {// 前面有东西,且是数字或者)
input_String.add("*"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "*"; // 运算符添加进表达式字符串
}
input_String.add("("); // 入列运算符
parenthesis_n += 1;
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "("; // 运算符添加进表达式字符串
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
} else if (button.getId() == R.id.button_right_parenthesis) {
//右括号可以出现在数字的右边,和右括号右边,如果没有右括号且当前没有输入数字,什么也不做
if (parenthesis_n > 0) {//前面有左括号才能加右括号,
if (!str_t_digit.equals("")) {//有数字
digit_t = Double.parseDouble(str_t_digit);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_digit;
str_t_digit = ""; //删除之前的数字字符串
input_Boolean.add(true);// 入列了一个数字
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
} else if (str_t_equation.charAt(str_t_equation.length() - 1) != ')') {
return;//没括号就润
}
input_String.add(")"); // 入列运算符
parenthesis_n -= 1;
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
}
} else {
Log.e("parenthesis", "error");
}
} catch (Exception e) {
Log.e("parenthesis", "error");
}
}
};
private final View.OnClickListener index_onClickListener = new View.OnClickListener() {//指数的侦听器,
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {// 指数和常用运算符逻辑相似,
if (!str_t_digit.equals("")) {//有数字
digit_t = Double.parseDouble(str_t_digit);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_digit;
str_t_digit = ""; //删除之前的数字字符串
input_Boolean.add(true);// 入列了一个数字
// 根据按钮入列运算符------------------------------
} else {// 如果输入数字为空,多种情况,
//前面是+-*/就替换,是)和数字直接加上去,(和""不管
// 前面什么都没有,但是textView_Now不空
if (str_t_equation.equals("") && !str_t_Now.equals("") && !str_t_Now.equals("错误")) {
//将textView_Now内容当数字进来
digit_t = Double.parseDouble(str_t_Now);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_Now;
input_Boolean.add(true);// 入列了一个数字
} else if (str_t_equation.equals("") || str_t_equation.charAt(str_t_equation.length() - 1) == '(') {
return;
} else {
if ("+-*/".contains(String.valueOf(str_t_equation.charAt(str_t_equation.length() - 1)))) {//前面是+-*/之一
input_String.remove(input_String.size() - 1); // 删除这个运算符
input_Boolean.remove(input_Boolean.size() - 1);
str_t_equation = str_t_equation.substring(0, str_t_equation.length() - 1); //表达式中删除这个运算符
//根据运算符添加---------------------
}
// 是)和数字
// 根据按钮入列运算符------------------------------
}
}
//先添加^(,再根据里面内容加入其他东西
input_String.add("^"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "^"; // 运算符添加进表达式字符串
input_String.add("("); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "("; // 运算符添加进表达式字符串
parenthesis_n += 1;
if (button.getId() == R.id.button_reciprocal) {
input_Double.add(0.0);// 入列了一个数字
str_t_equation += "0"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add("-"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "-"; // 运算符添加进表达式字符串
input_Double.add(1.0);// 入列了一个数字
str_t_equation += "1"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add(")"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
parenthesis_n -= 1;
} else if (button.getId() == R.id.button_square) {
input_Double.add(2.0);// 入列了一个数字
str_t_equation += "2"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add(")"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
parenthesis_n -= 1;
} else if (button.getId() == R.id.button_cubic_power) {
input_Double.add(3.0);// 入列了一个数字
str_t_equation += "3"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add(")"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
parenthesis_n -= 1;
} else if (button.getId() == R.id.button_n_power) {
//n次自己输入
} else if (button.getId() == R.id.button_square_root) {
input_Double.add(1.0);// 入列了一个数字
str_t_equation += "1"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add("/"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "/"; // 运算符添加进表达式字符串
input_Double.add(2.0);// 入列了一个数字
str_t_equation += "2"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add(")"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
parenthesis_n -= 1;
} else if (button.getId() == R.id.button_cube_root) {
input_Double.add(1.0);// 入列了一个数字
str_t_equation += "1"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add("/"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "/"; // 运算符添加进表达式字符串
input_Double.add(3.0);// 入列了一个数字
str_t_equation += "3"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add(")"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
parenthesis_n -= 1;
} else if (button.getId() == R.id.button_n_root) {
input_Double.add(1.0);// 入列了一个数字
str_t_equation += "1"; // 运算符添加进表达式字符串
input_Boolean.add(true);// 入列了一个数字
input_String.add("/"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "/"; // 运算符添加进表达式字符串
} else {
Log.e("index", "error");
return;
}
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
} catch (Exception e) {
Log.e("index_onClickListener", "error");
}
}
};
private final View.OnClickListener unary_operator_onClickListener = new View.OnClickListener() {//一元运算符,包含ln,log三角函数,inv
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {//先整inv,//单目运算符逻辑和左括号相似(毕竟包含左括号)
if (button.getId() == R.id.button_inv) {
mark_inv = !mark_inv;
if (mark_inv) {
button_sin.setText(R.string.sin);
button_cos.setText(R.string.cos);
button_tan.setText(R.string.tan);
} else {
button_sin.setText(R.string.sin_);
button_cos.setText(R.string.cos_);
button_tan.setText(R.string.tan_);
}
} else {//可以出现在非数字的右边,前面什么都没有也行,如果是数字或者),前面添加一个乘号
if (!input_Boolean.isEmpty() && (input_Boolean.get(input_Boolean.size() - 1) || str_t_equation.charAt(str_t_equation.length() - 1) == ')')) {// 前面有东西,且是数字或者)
input_String.add("*"); // 入列运算符
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "*"; // 运算符添加进表达式字符串
}
if (button.getId() == R.id.button_ln) {
input_String.add("ln"); // 入列运算符
str_t_equation += "ln"; // 运算符添加进表达式字符串
} else if (button.getId() == R.id.button_log) {
input_String.add("log"); // 入列运算符
str_t_equation += "log"; // 运算符添加进表达式字符串
} else if (button.getId() == R.id.button_sin) {
if (mark_inv) {
input_String.add("sin"); // 入列运算符
str_t_equation += "sin"; // 运算符添加进表达式字符串
} else {
input_String.add("sin⁻¹"); // 入列运算符
str_t_equation += "sin⁻¹"; // 运算符添加进表达式字符串
}
} else if (button.getId() == R.id.button_cos) {
if (mark_inv) {
input_String.add("cos"); // 入列运算符
str_t_equation += "cos"; // 运算符添加进表达式字符串
} else {
input_String.add("cos⁻¹"); // 入列运算符
str_t_equation += "cos⁻¹"; // 运算符添加进表达式字符串
}
} else if (button.getId() == R.id.button_tan) {
if (mark_inv) {
input_String.add("tan"); // 入列运算符
str_t_equation += "tan"; // 运算符添加进表达式字符串
} else {
input_String.add("tan⁻¹"); // 入列运算符
str_t_equation += "tan⁻¹"; // 运算符添加进表达式字符串
}
} else {
Log.e("unary_operator", "error");
return;
}
input_Boolean.add(false);// 入列了一个运算符
//都要进来一个(
input_String.add("("); // 入列运算符
parenthesis_n += 1;
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += "("; // 运算符添加进表达式字符串
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
}
} catch (Exception e) {
Log.e("unary_operator", "error");
}
}
};
private final View.OnClickListener delete_onClickListener = new View.OnClickListener() {//退位和清空侦听器,
@Override
public void onClick(View view) {//点击事件
Button button = (Button) view; //把点击获得的id信息传递给button
try {
if (button.getId() == R.id.button_C) { // 清空,第一次删除数字,然后算式,最后上次结果
if (!str_t_digit.equals("")) { // 有数字
str_t_digit = "";//清空数字
} else if (!str_t_equation.equals("")) { //有表达式
str_t_equation = "";// 清空表达式
parenthesis_n = 0;
input_String.clear();
input_Double.clear();
input_Boolean.clear();
} else {
str_t_Now = "";// 清空上次结果
}
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
textView_Now.setText(str_t_Now);
} else if (button.getId() == R.id.button_CE) { // 单纯的数字退格改为没数字退格表达式
if (!str_t_digit.equals("")) { // 有数字
str_t_digit = str_t_digit.substring(0, str_t_digit.length() - 1);
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
} else { // 退位表达式,出栈,注意特殊运算符的处理,括号的处理
if (!input_Boolean.isEmpty()) { // 表达式有东西才处理
if (input_Boolean.get(input_Boolean.size() - 1)) { // 最右边是数字,按目前设定不太可能出现这种情况
Log.e("delete", "需要弹出字符串。");
} else {
String pop_string = input_String.get(input_String.size() - 1); // 记录删除的运算符
input_String.remove(input_String.size() - 1);
input_Boolean.remove(input_Boolean.size() - 1);
str_t_equation = str_t_equation.substring(0, str_t_equation.lastIndexOf(pop_string)); // 字符串删除运算符
//(),常用运算符,特殊运算符
if (pop_string.equals("(")) { //出来的是左括号,判断是左边否为特殊运算符
parenthesis_n -= 1; //减少未匹配括号
if (!input_Boolean.isEmpty() && !input_Boolean.get(input_Boolean.size() - 1)) {
//前面有东西,并且是运算符,
if (special_symbols.contains(input_String.get(input_String.size() - 1))) {
//而且这个运算符还是特殊运算符
//删除这个特殊运算符
str_t_equation = str_t_equation.substring(0, str_t_equation.lastIndexOf(input_String.get(input_String.size() - 1))); // 字符串删除特殊运算符
input_String.remove(input_String.size() - 1);
input_Boolean.remove(input_Boolean.size() - 1);
}
//左边还有可能是^(,的形式,也一起删了
else if (input_String.get(input_String.size() - 1).equals("^")) {
str_t_equation = str_t_equation.substring(0, str_t_equation.lastIndexOf(input_String.get(input_String.size() - 1))); // 字符串删除^
input_String.remove(input_String.size() - 1);
input_Boolean.remove(input_Boolean.size() - 1);
//如果左边是数字一并删除数字
if (!input_Boolean.isEmpty() && input_Boolean.get(input_Boolean.size() - 1)) {
input_Double.remove(input_Double.size() - 1);
input_Boolean.remove(input_Boolean.size() - 1);
if (!input_String.isEmpty()) {
str_t_equation = str_t_equation.substring(0, str_t_equation.lastIndexOf(input_String.get(input_String.size() - 1)) + input_String.get(input_String.size() - 1).length()); // 字符串删除数字
} else { // 前面没东西了
str_t_equation = ""; //清空
}
}
}
// +(,-(等不用在意
}
} else { // 那就是+-*/)
if (pop_string.equals(")")) { //出来的是右括号,未匹配括号+1
parenthesis_n += 1; //增加未匹配括号
}
//如果左边是数字一并删除数字
if (!input_Boolean.isEmpty() && input_Boolean.get(input_Boolean.size() - 1)) {
input_Double.remove(input_Double.size() - 1);
input_Boolean.remove(input_Boolean.size() - 1);
if (!input_String.isEmpty()) {
str_t_equation = str_t_equation.substring(0, str_t_equation.lastIndexOf(input_String.get(input_String.size() - 1)) + input_String.get(input_String.size() - 1).length()); // 字符串删除数字
} else { // 前面没东西了
str_t_equation = ""; //清空
}
}
}
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
}
}
}
} else {
Log.e("delete", "error");
}
} catch (Exception e) {
Log.e("delete", "big error");
}
}
};
private final View.OnClickListener equal_To_onClickListener = new View.OnClickListener() {//等于号侦听器
@Override
public void onClick(View view) {//点击事件
//看看算式最右边是不是除了)的运算符,是的话看看当前有没有数字,有的话加进表达式中
if (!input_Boolean.isEmpty()) {
if (!input_Boolean.get(input_Boolean.size() - 1) && str_t_equation.charAt(str_t_equation.length() - 1) != ')') {
//最右边是非)的运算符
if (!str_t_digit.equals("")) {//有数字
digit_t = Double.parseDouble(str_t_digit);// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += str_t_digit;
str_t_digit = ""; //删除之前的数字字符串
input_Boolean.add(true);// 入列了一个数字
} else {//没数字就补个0吧
digit_t = 0.0;// 字符串转数字
input_Double.add(digit_t);// 入列
//数字添加进表达式字符串
str_t_equation += "0";
input_Boolean.add(true);// 入列了一个数字
}
}
if (parenthesis_n > 0) {// 看看当前有没有没写的),有的话加进表达式中,
while (parenthesis_n > 0) {
input_String.add(")"); // 入列运算符
parenthesis_n -= 1;
input_Boolean.add(false);// 入列了一个运算符
str_t_equation += ")"; // 运算符添加进表达式字符串
}
}
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
str_t_Now = count_String();//计算算式
} else {//表达式什么都没有
//直接结果0
str_t_Now = "0";
}
textView_Now.setText(str_t_Now);
editText.setText(str_t_digit);
editText.setSelection(editText.getText().length());
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
//清空表达式
input_String.clear();
input_Double.clear();
input_Boolean.clear();
str_t_equation = "";
//暂时不需要重新显示,让用户看一会
}
public String count_String() {
// 对输入的字符串进行计算,如果有错误,返回”错误“,没有返回计算结果
try {//用栈计算
Stack numStack = new Stack<>();//数字栈
Stack symbolStack = new Stack<>();//符号栈
String str_pop;// 出栈的运算符
int priority1, priority2;
Double numeral1, numeral2;
// 首尾添加#
input_String.add(0, "#");
input_Boolean.add(0, false);
input_String.add("#");
input_Boolean.add(false);
// 优先级是^>*=/>+=->(=)=单目>#,()和单目运算符特殊处理
while (!input_Boolean.isEmpty()) {//没东西就停下
if (input_Boolean.get(0)) {//数字直接入数字栈就行
input_Boolean.remove(0);
numStack.push(input_Double.remove(0));
} else {//运算符开始看情况
//(,三角函数,ln,log直接入,
//按优先级来,优先级高的碰到优先级低的直接入栈,低的碰到高的就出栈计算,
if (special_symbols.contains(input_String.get(0)) || "(".equals(input_String.get(0)) || symbolStack.empty()) {
//是特殊字符串,或者栈为空,直接入栈
input_Boolean.remove(0);
symbolStack.push(input_String.remove(0));
} else {
priority1 = get_priority(input_String.get(0));
priority2 = get_priority(symbolStack.peek());
if (priority1 == -1 || priority2 == -1) {
Log.e("equal_To", "数字栈不足");
return "错误";
}
if (priority1 > priority2) {// 否则看看两者优先级
// 如果外面的优先级大,就入栈
input_Boolean.remove(0);
symbolStack.push(input_String.remove(0));
} else {//否则,出栈看看
str_pop = symbolStack.pop();//出栈一个运算符
//根据出栈的运算符,判断要做的事情
if (str_pop.equals("(")) {//出来个左括号,后面只有可能是),不然有错误
if (input_String.get(0).equals(")")) {//是)就出栈,并看看前面是不是单目运算符
input_Boolean.remove(0);
input_String.remove(0);
if (special_symbols.contains(symbolStack.peek())) {//前面是特殊运算符
//获得特殊运算符
str_pop = symbolStack.pop();
//出栈一个元素,做出运算后再入栈
numeral1 = numStack.pop();
switch (str_pop) {
case "ln":
numStack.push(Math.log(numeral1));
break;
case "log":
numStack.push(Math.log10(numeral1));
break;
case "sin":
numStack.push(Math.sin(numeral1));
break;
case "cos":
numStack.push(Math.cos(numeral1));
break;
case "tan":
numStack.push(Math.tan(numeral1));
break;
case "sin⁻¹":
numStack.push(Math.asin(numeral1));
break;
case "cos⁻¹":
numStack.push(Math.acos(numeral1));
break;
case "tan⁻¹":
numStack.push(Math.atan(numeral1));
break;
default:
Log.e("equal_To", "左括号左边有其他运算符");
return "错误";
}
}
} else {
Log.e("equal_To", "左括号出栈时,右边不是右括号");
return "错误";
}
} else if (str_pop.equals("#")) {//如果出来个#
input_Boolean.remove(0);// 后面只能一个#,出来吧
input_String.remove(0);// 如果算式正确,循环接下来就会结束
} else {//双目运算符,出来两个数
numeral2 = numStack.pop();//这里就不判断栈是否空了,如果空,会进入try错误处理
numeral1 = numStack.pop();
switch (str_pop) {
case "^":
numStack.push(Math.pow(numeral1, numeral2));
break;
case "+":
numStack.push(numeral1 + numeral2);
break;
case "-":
numStack.push(numeral1 - numeral2);
break;
case "*":
numStack.push(numeral1 * numeral2);
break;
case "/":
if (numeral2 == 0) {
Log.e("equal_To", "除数为0");
return "错误";
}
numStack.push(numeral1 / numeral2);
break;
default:
Log.e("equal_To", "非正常常用运算符");
return "错误";
}
}
}
}
}
}
//循环结束,如果此时符号栈还有东西,或者数字栈多于一个数,就报错
if (!symbolStack.empty() || numStack.size() > 1) {
Log.e("equal_To", "循环结束后,栈内还有东西");
while (!symbolStack.empty()) {
Log.e("equal_To", "符号栈内东西有:" + symbolStack.pop());
}
while (!numStack.empty()) {
Log.e("equal_To", "数字栈内东西有:" + numStack.pop().toString());
}
return "错误";
} else {
return nf.format(numStack.pop());
}
} catch (Exception e) {
Log.e("equal_To", "其他错误" + e.toString());
return "错误";
}
}
public int get_priority(String str) {// 返回优先级
switch (str) {
case "^":
return 4;
case "*":
case "/":
return 3;
case "+":
case "-":
return 2;
case "(":
case ")":
return 1;
case "#":
return 0;
default:
return -1;
}
}
};
// 被销毁前缓存一些数据,为了旋转后不出问题
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putDouble("memory", memory);
outState.putInt("parenthesis_n", parenthesis_n);
outState.putString("str_t_digit", str_t_digit);
outState.putString("str_t_equation", str_t_equation);
outState.putString("str_t_Now", str_t_Now);
outState.putSerializable("input_Double", input_Double);
outState.putSerializable("input_String", input_String);
outState.putSerializable("input_Boolean", input_Boolean);
}
//下面这个重写了父类的方法,会在程序启动时调用,
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // 调用父类的onCreate()方法
setContentView(R.layout.activity_main); // 布局文件的位置
special_symbols.add("ln");
special_symbols.add("log");
special_symbols.add("sin");
special_symbols.add("cos");
special_symbols.add("tan");
special_symbols.add("sin⁻¹");
special_symbols.add("cos⁻¹");
special_symbols.add("tan⁻¹");
nf.setGroupingUsed(false);//不使用12,345,789这样的三位格式化
nf.setMaximumFractionDigits(16);// 最大保留16位小数
nf.setMinimumFractionDigits(0);// 最小保留16位小数
// 获取文本框引用
editText = findViewById(R.id.textView_Equation);
textView = findViewById(R.id.textView_Last);
textView_Now = findViewById(R.id.textView_Now);
//滚动控件引用
horizonLayout_Last = findViewById(R.id.horizonLayout_Last);
horizonLayout_Now = findViewById(R.id.horizonLayout_Now);
//文本框赋值会自动移动光标到最左边,记着移回最右边
// 上面带滚动条的把滚动条移到最右边
// 禁止弹出文本框,并且不允许长按,以防粘贴进奇奇怪怪的东西
editText.setShowSoftInputOnFocus(false);
editText.setLongClickable(false);
if (savedInstanceState != null) {
// 从保存的 Bundle 中恢复数据
memory = savedInstanceState.getDouble("memory");
parenthesis_n = savedInstanceState.getInt("parenthesis_n");
str_t_digit = savedInstanceState.getString("str_t_digit");
str_t_equation = savedInstanceState.getString("str_t_equation");
str_t_Now = savedInstanceState.getString("str_t_Now");
input_Double = (ArrayList) savedInstanceState.getSerializable("input_Double");
input_String = (ArrayList) savedInstanceState.getSerializable("input_String");
input_Boolean = (ArrayList) savedInstanceState.getSerializable("input_Boolean");
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
}
textView.setText(str_t_equation);
horizonLayout_Last.fullScroll(View.FOCUS_RIGHT);// 滑动到最右边
textView_Now.setText(str_t_Now);
editText.setText(str_t_digit);
// 光标移动
editText.setSelection(editText.getText().length());
// 获取按钮引用
//旋转
button_rotate = findViewById(R.id.button_rotate);
// 数字
number_buttons[0] = findViewById(R.id.button_0);
number_buttons[1] = findViewById(R.id.button_1);
number_buttons[2] = findViewById(R.id.button_2);
number_buttons[3] = findViewById(R.id.button_3);
number_buttons[4] = findViewById(R.id.button_4);
number_buttons[5] = findViewById(R.id.button_5);
number_buttons[6] = findViewById(R.id.button_6);
number_buttons[7] = findViewById(R.id.button_7);
number_buttons[8] = findViewById(R.id.button_8);
number_buttons[9] = findViewById(R.id.button_9);
// 小数点
button_point = findViewById(R.id.button_point);
// 常用运算符
button_add = findViewById(R.id.button_add);
button_sub = findViewById(R.id.button_sub);
button_mul = findViewById(R.id.button_mul);
button_div = findViewById(R.id.button_div);
// 等于号
button_equal_To = findViewById(R.id.button_equal_To);
// 两个删除
button_C = findViewById(R.id.button_C);
button_CE = findViewById(R.id.button_CE);
// 记忆变量相关
textView_M = findViewById(R.id.textView_M);
if (memory == 0.0) {
textView_M.setText("");
}// 隐藏M标志
button_MC = findViewById(R.id.button_MC);
button_Mup = findViewById(R.id.button_Mup);
button_Mdown = findViewById(R.id.button_Mdown);
button_MR = findViewById(R.id.button_MR);
// 横屏运算符
// 两个括号
button_left_parenthesis = findViewById(R.id.button_left_parenthesis);
button_right_parenthesis = findViewById(R.id.button_right_parenthesis);
//两个特殊变量
button_e = findViewById(R.id.button_e);
button_pi = findViewById(R.id.button_pi);
// 倒数,二次方,三次方,n次方,
button_reciprocal = findViewById(R.id.button_reciprocal);
button_square = findViewById(R.id.button_square);
button_cubic_power = findViewById(R.id.button_cubic_power);
button_n_power = findViewById(R.id.button_n_power);
// 平方根,立方根,n次根
button_square_root = findViewById(R.id.button_square_root);
button_cube_root = findViewById(R.id.button_cube_root);
button_n_root = findViewById(R.id.button_n_root);
// 切换一元运算符的按钮(反函数)
button_inv = findViewById(R.id.button_inv);
//ln,log
button_ln = findViewById(R.id.button_ln);
button_log = findViewById(R.id.button_log);
// 三角函数们
button_sin = findViewById(R.id.button_sin);
button_cos = findViewById(R.id.button_cos);
button_tan = findViewById(R.id.button_tan);
// 为按钮添加监听器
button_rotate.setOnClickListener(land_switch_onClickListener);
button_point.setOnClickListener(digit_onClickListener);
number_buttons[0].setOnClickListener(digit_onClickListener);
number_buttons[1].setOnClickListener(digit_onClickListener);
number_buttons[2].setOnClickListener(digit_onClickListener);
number_buttons[3].setOnClickListener(digit_onClickListener);
number_buttons[4].setOnClickListener(digit_onClickListener);
number_buttons[5].setOnClickListener(digit_onClickListener);
number_buttons[6].setOnClickListener(digit_onClickListener);
number_buttons[7].setOnClickListener(digit_onClickListener);
number_buttons[8].setOnClickListener(digit_onClickListener);
number_buttons[9].setOnClickListener(digit_onClickListener);
button_add.setOnClickListener(operator_onClickListener);
button_sub.setOnClickListener(operator_onClickListener);
button_mul.setOnClickListener(operator_onClickListener);
button_div.setOnClickListener(operator_onClickListener);
button_C.setOnClickListener(delete_onClickListener);
button_CE.setOnClickListener(delete_onClickListener);
button_equal_To.setOnClickListener(equal_To_onClickListener);
button_MC.setOnClickListener(memory_onClickListener);
button_Mup.setOnClickListener(memory_onClickListener);
button_Mdown.setOnClickListener(memory_onClickListener);
button_MR.setOnClickListener(memory_onClickListener);
// 两个括号
button_left_parenthesis.setOnClickListener(parenthesis_onClickListener);
button_right_parenthesis.setOnClickListener(parenthesis_onClickListener);
//两个特殊变量
button_e.setOnClickListener(memory_onClickListener);
button_pi.setOnClickListener(memory_onClickListener);
// 倒数,二次方,三次方,n次方,
button_reciprocal.setOnClickListener(index_onClickListener);
button_square.setOnClickListener(index_onClickListener);
button_cubic_power.setOnClickListener(index_onClickListener);
button_n_power.setOnClickListener(index_onClickListener);
// 平方根,立方根,n次根
button_square_root.setOnClickListener(index_onClickListener);
button_cube_root.setOnClickListener(index_onClickListener);
button_n_root.setOnClickListener(index_onClickListener);
// 切换一元运算符的按钮(反函数)
button_inv.setOnClickListener(unary_operator_onClickListener);
//ln,log
button_ln.setOnClickListener(unary_operator_onClickListener);
button_log.setOnClickListener(unary_operator_onClickListener);
// 三角函数们
button_sin.setOnClickListener(unary_operator_onClickListener);
button_cos.setOnClickListener(unary_operator_onClickListener);
button_tan.setOnClickListener(unary_operator_onClickListener);
}
}
drawable中,设置的几个blackbutton之类的,以button或buttons结尾命名的文件是selector,其中是不同颜色的圆角按钮的定义,将设定好的selector用作按钮的背景就可以整出异形按钮了,这里使用的都是圆角按钮。那两个ic打头的本来是初始自带的图标但我更改了图标,所以没什么用了。
首先把你想整的图片粘贴进drawable目录,虽然是虚拟目录,但能直接粘贴进去。
使用快捷键Ctrl+Shift+A,会弹出搜索框,输入im选择第一个,就是那个带安卓图标的Image Asset。
然后把前景替换就行,第二个是背景,我直接设成白色了,图片是我自己画的,怕被拉去要钱。过一段时间整一个个人logo。
具体的在网上查查Image Asset的使用之类的。设置完了就会虚拟目录就会多一个mipmap
这几个按钮的xml都大同小异,看一个剩下的就不用看了,只是改改颜色而已,建议去看看布局。里面的@color/***都是在colors.xml中定义的,八位16进制颜色和6位16进制颜色都可以。
-
-
-
-
-
-
-
-
-
-
布局文件,一个竖屏,一个横屏,横屏刚开始没有,你换成系统目录视图,在layout-land创建就行
本来使用的网格布局,后来发现p30上显示有问题,换成约束布局了,约束布局就别敲代码了,可视化整的方便些,就是可能会有些卡。约束布局也是大同小异,稍微值得注意的就是这里使用了一些横向滚动容器来装文本控件。使用style来统一设定。
我该最后粘贴代码的,越写越卡了。
一些颜色的定义,获得16进制颜色有很多方法,我用的是画图3D来取色,你也可以用它打开图片,然后直接选中图片的颜色。后续版本我会添加多页面,可能会添加相应功能(画大饼,大概率不写)
#FF000000
#FFFFFFFF
#000000
#303030
#404040
#FFFFFF
#506EF0
#2A40C0
#FFBB40
#FFA400
#EAEAEE
#CDCDD2
#9696A0
定义字符串的,其中,第一个name="app_name"这个,设定的是应用的名字,就是图标下面显示的名字。
i道i的计算器
i道i
M
MR
M+
M-
MC
+
-
×
÷
C
退格
.
=
0
1
2
3
4
5
6
7
8
9
⇵
错误
NULL
e
π
(
)
1/x
x²
x³
xⁿ
²√
³√
ⁿ√
Inv
ln
log
eⁿ
10ⁿ
sin
cos
tan
sin⁻¹
cos⁻¹
tan⁻¹
当你创建多个styles.xml文件时,虚拟目录这里才会给你整个文件夹包起来,项目目录如下:
带-night是暗色模式使用的,就是你手机上的深色模式,如果深色模式文件夹里有就会用深色模式文件夹里的,没有就用浅色模式中的东西。
styles.xml初始是不自带的,你需要自己创建。
说起来也是大同小异,这东西相当于设定一个模板,然后你就在布局中套用这个模板就行。跟类一样,甚至可以继承。
我这设置的两个都一样的,改了一下主题,就是第一个parent后面的东西。其实就是默认style继承的东西。其他的自动生成没动