鸿蒙 简易计算器实现案例教程【鸿蒙专题8】

准备工作

华为鸿蒙系统开发初体验 :https://www.jianshu.com/p/f94c847c7fdc

效果图:

image.png

具体实现

  • 代码结构

image.png

  • 1 slice MainAbilitySlice:计算器交互界面,用于完成界面元素渲染、按钮事件绑定动作。
  • 2 utils
  • MathUtil:用于计算表达式结果的工具类,封装有运算符权重获取、表达式计算等方法。
  • 3 resources resourcesbaselayout:存放xml布局文件。resourcesbasemedia:存放图片资源文件。resourcesbasegraphic:存放xml样式文件。
  • 4 MainAbility:HAP的入口ability,由DevEco Studio自动生成。
  • 5 MyApplication:表示HAP的类,由DevEco Studio自动生成。
  • 6 config.json:应用的配置文件,由DevEco Studio自动生成。
  • 应用初始化
    计算器应用使用的是自定义的按键,为避免用户在输入数学表达式时,系统自动弹出软键盘,本应用在初始化时,会在入口类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
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
    xmlns:ohos="http://schemas.huawei.com/res/ohos"
    ohos:height="match_parent"
    ohos:orientation="vertical"
    ohos:alignment="bottom"
    ohos:background_element="$graphic:background_ability_main"
    ohos:width="match_parent">

    <DirectionalLayout
        ohos:id="$+id:result_console"
        ohos:height="match_content"
        ohos:left_margin="15vp"
        ohos:right_margin="15vp"
        ohos:bottom_margin="50vp"
        ohos:width="match_parent">

        <TextField
            ohos:id="$+id:input_text"
            ohos:height="60vp"
            ohos:width="match_parent"
            ohos:text_size="48vp"
            ohos:bubble_height="0"
            ohos:multiple_lines="false"
            ohos:text_alignment="right"/>

        <Text
            ohos:id="$+id:pre_result"
            ohos:margin="3vp"
            ohos:height="42vp"
            ohos:width="match_parent"
            ohos:text_size="36vp"
            ohos:text_color="#555555"
            ohos:scrollable="true"
            ohos:text_alignment="right"/>

    </DirectionalLayout>

    <DirectionalLayout
        ohos:id="$+id:calculate_keyboard"
        ohos:height="match_content"
        ohos:padding="8vp"
        ohos:margin="8vp"
        ohos:background_element="$graphic:background_keyboard"
        ohos:width="match_parent">

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:alignment="center"
            ohos:orientation="horizontal">

            <Text
                ohos:id="$+id:number_cancel"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:text_color="blue"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="C"/>

            <Text
                ohos:id="$+id:divide"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="35vp"
                ohos:text_color="blue"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="÷"/>

            <Text
                ohos:id="$+id:multiply"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="35vp"
                ohos:text_color="blue"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="×"/>

            <Image
                ohos:id="$+id:delete"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="28vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:image_src="$media:brief_del_bt"
                />
        </DirectionalLayout>

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:alignment="center"
            ohos:orientation="horizontal">

            <Text
                ohos:id="$+id:seven"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="7"/>

            <Text
                ohos:id="$+id:eight"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="8"/>

            <Text
                ohos:id="$+id:nine"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="9"/>

            <Text
                ohos:id="$+id:minus"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_color="blue"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="-"/>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:alignment="center"
            ohos:orientation="horizontal">

            <Text
                ohos:id="$+id:four"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="4"/>

            <Text
                ohos:id="$+id:five"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="5"/>

            <Text
                ohos:id="$+id:six"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="6"/>

            <Text
                ohos:id="$+id:plus"
                ohos:text_alignment="center"
                ohos:height="70vp"
                ohos:width="70vp"
                ohos:text_color="blue"
                ohos:text_size="30vp"
                ohos:background_element="$graphic:background_round"
                ohos:margin="8vp"
                ohos:text="+"/>
        </DirectionalLayout>

        <DirectionalLayout
            ohos:height="match_content"
            ohos:width="match_parent"
            ohos:orientation="horizontal"
            ohos:alignment="center">
            <DirectionalLayout
                ohos:height="match_content"
                ohos:width="match_content">

                <DirectionalLayout
                    ohos:height="match_content"
                    ohos:width="match_parent"
                    ohos:alignment="center"
                    ohos:orientation="horizontal">

                    <Text
                        ohos:id="$+id:one"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="1"/>

                    <Text
                        ohos:id="$+id:two"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="2"/>

                    <Text
                        ohos:id="$+id:three"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="3"/>
                </DirectionalLayout>

                <DirectionalLayout
                    ohos:height="match_content"
                    ohos:width="match_parent"
                    ohos:alignment="center"
                    ohos:orientation="horizontal">

                    <Text
                        ohos:id="$+id:divide_remainder"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="%"/>

                    <Text
                        ohos:id="$+id:zero"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="0"/>

                    <Text
                        ohos:id="$+id:radix_point"
                        ohos:text_alignment="center"
                        ohos:height="70vp"
                        ohos:width="70vp"
                        ohos:text_size="30vp"
                        ohos:background_element="$graphic:background_round"
                        ohos:margin="8vp"
                        ohos:text="."/>
                </DirectionalLayout>

            </DirectionalLayout>

            <Text
                ohos:id="$+id:equal_sign"
                ohos:text_alignment="center"
                ohos:height="150vp"
                ohos:width="70vp"
                ohos:text_size="35vp"
                ohos:text_color="#FFFFFF"
                ohos:background_element="$graphic:background_denghao"
                ohos:margin="8vp"
                ohos:text="="/>
        </DirectionalLayout>

    </DirectionalLayout>

</DirectionalLayout>

布局预览效果

我们从布局文件结构·可以看出来 多层线性布局嵌套来实现了整个 计算器键盘的布局 以及输入框和显示结果的text

  • 逻辑实现
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() &amp;&amp; ".".equals(inputValue)) {
            return;
        }
        if ("0".equals(oldValue) &amp;&amp; !".".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))
                &amp;&amp; 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);
    }
}

我们定义了2个数组来统一初始化我们的运算键位控件和我们数字控件 并且添加点击事件,然后配合我们MathUtil 工具类来处理结果

  • cancel 清零复位键处理
      findComponentById(ResourceTable.Id_number_cancel).setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                preResult.setText("");
                inputText.setText("");
            }
        });


当用户点击到cancel键的时候我们将输入框的内容和显示文本上的内容全部都set成空字符串

  • 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));
            }
        });

当用户点击到delete我们采用的 末尾删除 这个时候我们只需要通过字符串截取即可实现

具体 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&lt;&gt;();
        numStack.push(separateStr); // 数字用@分开,数字栈中@号 为了便于区分小数
        Stack oprStack = new Stack&lt;&gt;();

        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() &amp;&amp; priority(singleStr) &lt;= 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) &gt; NOT_CONTAIN) {
            return true;
        }
        return false;
    }

    private static int priority(String str) {
        String highOperator = "×÷%";
        if (highOperator.indexOf(str) &gt; NOT_CONTAIN) {
            return HIGH_PRIORITY;
        }
        return LOW_PRIORITY;
    }
}

工具类是借鉴了java里面数据学运算的设计 有兴趣的同学可以自己看一下这里不展开讲 到此简易计算器demo已经讲完了。

最后总结

这一章主要是讲解鸿蒙里面一些常用的案例 由于鸿蒙采用了java js作为基础语言来开发 非常成熟的语言那么我们在java以及js里面比较成熟的 数学运算设计可以直接借鉴的 我们配合上UI 布局就可以实现类似的简易计算器,有兴趣的可以私下多研究看看用js ui如何实现 这里就不展开讲了. 最后希望我的文章能帮助到各位解决问题 ,以后我还会贡献更多有用的代码分享给大家。各位同学如果觉得文章还不错 ,麻烦给关注和star,小弟在这里谢过啦

项目地址

码云 :https://gitee.com/qiuyu123/counter_demo

今天的文章就分享到这儿,如果大家喜欢的话,我将会在接下来的一段时间里,持续分享更多优质内容。

文章来源于互联网:鸿蒙 简易计算器实现案例教程【鸿蒙专题8】

阅读全文
下载说明:
1、本站所有资源均从互联网上收集整理而来,仅供学习交流之用,因此不包含技术服务请大家谅解!
2、本站不提供任何实质性的付费和支付资源,所有需要积分下载的资源均为网站运营赞助费用或者线下劳务费用!
3、本站所有资源仅用于学习及研究使用,您必须在下载后的24小时内删除所下载资源,切勿用于商业用途,否则由此引发的法律纠纷及连带责任本站和发布者概不承担!
4、本站站内提供的所有可下载资源,本站保证未做任何负面改动(不包含修复bug和完善功能等正面优化或二次开发),但本站不保证资源的准确性、安全性和完整性,用户下载后自行斟酌,我们以交流学习为目的,并不是所有的源码都100%无错或无bug!如有链接无法下载、失效或广告,请联系客服处理!
5、本站资源除标明原创外均来自网络整理,版权归原作者或本站特约原创作者所有,如侵犯到您的合法权益,请立即告知本站,本站将及时予与删除并致以最深的歉意!
6、如果您也有好的资源或教程,您可以投稿发布,成功分享后有站币奖励和额外收入!
7、如果您喜欢该资源,请支持官方正版资源,以得到更好的正版服务!
8、请您认真阅读上述内容,注册本站用户或下载本站资源即您同意上述内容!
原文链接:https://www.shuli.cc/?p=19184,转载请注明出处。
0

评论0

显示验证码
没有账号?注册  忘记密码?