Gradle配置
项目需要使用databinding特性,需要配置下build.gradle(Module)
android{
...
dataBinding{
enabled true
}
}
没有接触过databinding的同学可以移步此页面
https://github.com/LyndonChin/MasteringAndroidDataBinding
界面设计
... 就是TextView + N个Button的搭配,本人缺乏艺术细胞,详情请点击
http://www.sj33.cn/digital/uisj/201609/46378.html
本人设计的界面效果如下
- UI
代码设计
代码结构(很简单...)
code.png-
Compute
对中缀表达式转换成后缀表达式,并计算结果。
public class Compute {
public static String c(String infixExp){
String result;
try {
List<Object> posfix = infix2posfix(infixExp);
result = f(posfix);
}catch (Exception e){
result = Values.IRREGULAR_EXP;
}
return result;
}
private static String f(List<Object> list) {
Stack<BigDecimal> result = new Stack<>();
Iterator it = list.iterator();
while(it.hasNext()){
String m = it.next().toString();
if (m.equals(Values.ACTION_ADD)
|| m.equals(Values.ACTION_SUB)
|| m.equals(Values.ACTION_MUL)
|| m.equals(Values.ACTION_DIV)) {
BigDecimal b = result.pop();
BigDecimal a = result.pop();
BigDecimal v = g(a, b, m);
result.push(v);
}else {
result.push(new BigDecimal(m));
}
}
return(result.pop().toString());
}
private static BigDecimal g(BigDecimal a, BigDecimal b, String m) {
BigDecimal v = new BigDecimal("0.0");
switch (m) {
case Values.ACTION_ADD:
v = a.add(b);
break;
case Values.ACTION_SUB:
v = a.subtract(b);
break;
case Values.ACTION_MUL:
v = a.multiply(b);
break;
case Values.ACTION_DIV:
v = a.divide(b, Values.DEF_DIV_SCALE, BigDecimal.ROUND_HALF_UP);
break;
}
return v;
}
private static List<Object> infix2posfix(String s) {
Stack<Character> opsStack = new Stack<>();
ArrayList<Object> list = new ArrayList<>();
Pattern P = Pattern.compile("[0-9]+(\\.[0-9]+)?"); //正则表达式来处理带小数点的数字
int i=0;
while(i < s.length()){
char c = s.charAt(i);
if (c >='0' && c <= '9') {
String subStr = s.substring(i);
Matcher m = P.matcher(subStr);
if (m.find()) { //取匹配到的第一个数字
subStr = m.group();
list.add(subStr);
}
i = i + subStr.length();
continue;
} else if (c == '(') {
opsStack.push(c);
} else if (c == ')') {
while(opsStack.peek() != '('){
list.add(opsStack.pop());
}
//pop the '('
opsStack.pop();
} else if (c == '+' || c == '-') {
while(!opsStack.isEmpty() && opsStack.peek() != '('){
list.add(opsStack.pop());
}
opsStack.push(c);
}else if (c == '*'|| c == '/') {
while(!opsStack.isEmpty() && (opsStack.peek() =='*' || opsStack.peek() == '/')){
list.add(opsStack.pop());
}
opsStack.push(c);
}
i++;
}
while(!opsStack.isEmpty()){
list.add(opsStack.pop());
}
return list;
}
}
-
Update
初始化按钮响应事件,并更新表达式,得数。
public class Update {
private static String result = "";
public static void btnClickEventInit(final ActivityMainBinding binding){
/**
* inti number event
*/
binding.btnZero.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
appendText(binding, "0");
}
});
binding.btnOne.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
appendText(binding, "1");
}
});
... ...
binding.btnDot.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String exp = binding.textExp.getText().toString();
if (isDotabled(exp)) {
appendText(binding, ".");
}
}
});
/**
* init compute event
*/
binding.btnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String exp = binding.textExp.getText().toString();
if (isOperateable(exp)){
appendResultText(binding, "+");
}
}
});
... ...
binding.btnEqual.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String exp = binding.textExp.getText().toString();
result = Compute.c(exp);
binding.textExp.setText("");
binding.textResult.setText(result);
}
});
/**
* init clear & delete
*/
binding.btnClear.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
clearText(binding);
}
});
binding.btnDelete.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
deleteText(binding);
}
});
}
/**
* Handle text
*/
private static void appendText(final ActivityMainBinding binding, String append){
String oldExp = binding.textExp.getText().toString();
binding.setExpress(oldExp + append);
}
private static void clearText(final ActivityMainBinding binding){
result = "";
binding.setExpress("");
binding.setResult("");
}
private static void deleteText(final ActivityMainBinding binding){
String oldExp = binding.textExp.getText().toString();
if (oldExp != "") {
StringBuilder builder = new StringBuilder(oldExp);
binding.setExpress(builder.deleteCharAt(builder.length() - 1).toString());
}
}
private static void appendResultText(ActivityMainBinding binding, String op){
if (binding.textExp.getText().toString() != "") {
appendText(binding, op);
}
else {
appendText(binding, result + op);
}
}
/**
* check text
*/
private static boolean isOperateable(String exp){
if ((result != "" && result != Values.IRREGULAR_EXP)
|| (exp != "" && Character.isDigit(exp.charAt(exp.length() - 1)))) {
return true;
}
return false;
}
private static boolean isDotabled(String exp){
int lastPos = exp.length() - 1;
if (exp != ""
&& ('0' <= exp.charAt(lastPos) && exp.charAt(lastPos) <= '9')) {
for (int i = exp.length() - 1; i >= 0; i--) {
if (exp.charAt(i) == '.') {
return false;
} else if (exp.charAt(i) == '+'
|| exp.charAt(i) == '-'
|| exp.charAt(i) == '*'
|| exp.charAt(i) == '/') {
return true;
}
}
return true;
}
return false;
}
}
-
Values
就是一些变量咯...
public class Values {
public static final String IRREGULAR_EXP = "错误";
public static final String ACTION_ADD = "+";
public static final String ACTION_SUB = "-";
public static final String ACTION_MUL = "*";
public static final String ACTION_DIV = "/";
public static final int DEF_DIV_SCALE = 10;
}
难点
- 中缀表达式的计算,借助栈将中缀表达式转换成后缀表达式,进而计算结果
- 浮点数的计算,起先用double类型时,会出现 0.3 * 6 = 1.7999999的bug,后采用BigDemical成功debug
- 表达式的规范,表达式末为数字时可以输入操作符(+-*/), 表达式末为数字且此数不为小数时可加小数点等
- databinding的使用,项目采用了单向数据绑定,简化了button等组件的初始化过程
不足
- 未实现负数计算功能
- 未实现科学计算功能
网友评论