简单计算器
效果图:
具体实现
- 代码结构
- 应用初始化
计算器应用使用的是自定义的按键,为避免用户在输入数学表达式时,系统自动弹出软键盘,本应用在初始化时,会在入口类MainAbility禁止应用弹出软键盘。
getWindow().setLayoutFlags(WindowManager.LayoutConfig.MARK_ALT_FOCUSABLE_IM, WindowManager.LayoutConfig.MARK_ALT_FOCUSABLE_IM);
随后会在计算器交互界面类MainAbilitySlice中,完成界面渲染和按键点击事件绑定。
@Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initView(); initListener(); }
- 主页面布局
布局文件 ability_main.xml
- 逻辑实现
package com.example.counter_demo.slice;import com.example.counter_demo.utils.MathUtil;import com.example.counter_demo.ResourceTable;import ohos.aafwk.ability.AbilitySlice;import ohos.aafwk.content.Intent;import ohos.agp.components.Component;import ohos.agp.components.Text;import ohos.agp.components.TextField;import java.util.EmptyStackException;import java.util.regex.Pattern;/** * MainAbilitySlice * * @since 2021年8月22日11:55:18 * */public class MainAbilitySlice extends AbilitySlice { /** * number component */ private static int[] numberComponentIds = {ResourceTable.Id_seven, ResourceTable.Id_eight, ResourceTable.Id_nine, ResourceTable.Id_four, ResourceTable.Id_five, ResourceTable.Id_six, ResourceTable.Id_one, ResourceTable.Id_two, ResourceTable.Id_three, ResourceTable.Id_zero, ResourceTable.Id_radix_point }; /** * operator component */ private static int[] operatorComponentIds = {ResourceTable.Id_divide, ResourceTable.Id_multiply, ResourceTable.Id_minus, ResourceTable.Id_divide_remainder, ResourceTable.Id_plus }; private TextField inputText; private Text preResult; @Override public void onStart(Intent intent) { super.onStart(intent); super.setUIContent(ResourceTable.Layout_ability_main); initView(); initListener(); } private void initView() { if (findComponentById(ResourceTable.Id_input_text) instanceof TextField) { inputText = (TextField) findComponentById(ResourceTable.Id_input_text); inputText.requestFocus(); } if (findComponentById(ResourceTable.Id_pre_result) instanceof Text) { preResult = (Text) findComponentById(ResourceTable.Id_pre_result); } } private void initListener() { findComponentById(ResourceTable.Id_number_cancel).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { preResult.setText(""); inputText.setText(""); } }); findComponentById(ResourceTable.Id_delete).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (inputText.getText().isEmpty()) { return; } inputText.setText(inputText.getText().substring(0, inputText.getText().length() - 1)); } }); findComponentById(ResourceTable.Id_equal_sign).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { calculateResult(inputText.getText(), false); } }); for (int componentId : numberComponentIds) { findComponentById(componentId).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { bindNumberClickListener(componentId); } }); } for (int componentId : operatorComponentIds) { findComponentById(componentId).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { bindOperatorClickListener(componentId); } }); } } private void bindNumberClickListener(int componentId) { String oldValue = inputText.getText(); String inputValue = ""; if (findComponentById(componentId) instanceof Text) { Text text = (Text) findComponentById(componentId); inputValue = text.getText(); } if (oldValue.isEmpty() && ".".equals(inputValue)) { return; } if ("0".equals(oldValue) && !".".equals(inputValue)) { inputText.setText(inputValue); } else { inputText.append(inputValue); } calculateResult(inputText.getText(), true); } private void bindOperatorClickListener(int componentId) { String oldValue = inputText.getText(); String inputValue = ""; if (findComponentById(componentId) instanceof Text) { Text text = (Text) findComponentById(componentId); inputValue = text.getText(); } if (oldValue.isEmpty()) { inputText.setText(inputValue); } else if (MathUtil.isOperator(oldValue.substring(oldValue.length() - 1)) && MathUtil.isOperator(inputValue)) { String newValue = oldValue.substring(0, oldValue.length() - 1) + inputValue; inputText.setText(newValue); } else { inputText.append(inputValue); } calculateResult(inputText.getText(), true); } private void calculateResult(String exp, Boolean isAutoCalculate) { if (exp.isEmpty()) { return; } // 只有数字 不计算 String pattern = "(\\d*\\.?\\d*)|(0\\.\\d*[1-9])"; boolean isMatch = Pattern.matches(pattern, exp); if (isMatch) { return; } // 末位是运算符 不计算 if (MathUtil.isOperator(exp.substring(exp.length() - 1))) { return; } String resultValue; try { resultValue = MathUtil.getResultString(exp); } catch (NumberFormatException | ArithmeticException | EmptyStackException e) { preResult.setText("错误"); return; } if (isAutoCalculate) { preResult.setText(resultValue); return; } preResult.setText(""); inputText.setText(resultValue); } @Override public void onActive() { super.onActive(); } @Override public void onForeground(Intent intent) { super.onForeground(intent); }}
- delete删除键处理
findComponentById(ResourceTable.Id_delete).setClickedListener(new Component.ClickedListener() { @Override public void onClick(Component component) { if (inputText.getText().isEmpty()) { return; } inputText.setText(inputText.getText().substring(0, inputText.getText().length() - 1)); } });
具体 MathUtil 工具类实现
package com.example.counter_demo.utils;import java.math.BigDecimal;import java.util.Stack;/** * MathUtil * * @since 2021年8月22日11:55:02 * 类说明:数学运算工具类 */public class MathUtil { // 数字栈中分隔数字时使用 private static String separateStr = "@"; // 保留小数位数 private static final int DECIMAL_DIGIT = 6; // 不包含指定字符 private static final int NOT_CONTAIN = -1; // 高优先级 private static final int HIGH_PRIORITY = 2; // 低优先级 private static final int LOW_PRIORITY = 1; private MathUtil() { } public static String getResultString(String exp) { Stack numStack = new Stack(); numStack.push(separateStr); // 数字用@分开,数字栈中@号 为了便于区分小数 Stack oprStack = new Stack(); String[] strings = exp.split(""); for (String singleStr : strings) { if (isOperator(singleStr)) { spiltExp(numStack, oprStack, singleStr); } else { numStack.push(singleStr); } } while (!oprStack.isEmpty()) { combineString(numStack); compute(numStack, oprStack); } numStack.pop(); String resultValue = numStack.peek(); return resultValue; } private static void spiltExp(Stack numStack, Stack oprStack, String singleStr) { // 运算符间的字符拼接成一个数字 combineString(numStack); if (!oprStack.isEmpty()) { // 先处理优先级高的运算符 while (!oprStack.isEmpty() && priority(singleStr) <= priority(oprStack.peek())) { combineString(numStack); compute(numStack, oprStack); } } oprStack.push(singleStr); } private static void compute(Stack numStack, Stack oprStack) { BigDecimal result = null; numStack.pop(); BigDecimal rightNumber = new BigDecimal(numStack.pop()); numStack.pop(); BigDecimal leftNumber = new BigDecimal(numStack.pop()); String operator = oprStack.pop(); switch (operator) { case "-": result = leftNumber.subtract(rightNumber); break; case "+": result = leftNumber.add(rightNumber); break; case "%": result = leftNumber.divideAndRemainder(rightNumber)[1]; break; case "×": result = leftNumber.multiply(rightNumber); break; case "÷": result = leftNumber.divide(rightNumber, DECIMAL_DIGIT, BigDecimal.ROUND_HALF_UP); break; default: break; } numStack.push(result.stripTrailingZeros().toPlainString()); numStack.push(separateStr); } private static void combineString(Stack stack) { if (separateStr.equals(stack.peek())) { return; } StringBuilder numberBuilder = new StringBuilder(); while (true) { String string = stack.peek(); if (separateStr.equals(string)) { break; } numberBuilder.insert(0, string); stack.pop(); } stack.push(numberBuilder.toString()); stack.push(separateStr); numberBuilder.delete(0, numberBuilder.length()); } /** * Determines whether a string is an operator. * * @param singleStr Character string to be judged * @return Judgment Result */ public static boolean isOperator(String singleStr) { String operators = "-+×÷%"; if (operators.indexOf(singleStr) > NOT_CONTAIN) { return true; } return false; } private static int priority(String str) { String highOperator = "×÷%"; if (highOperator.indexOf(str) > NOT_CONTAIN) { return HIGH_PRIORITY; } return LOW_PRIORITY; }}