Android 房租计算器,简单计算器

房租计算器

功能简介

1、根据入住时间,计算入住至今的月份间隔,x月x天;
2、自定义计算器,无括号,简单计算器;
3、使用SqLite存储计算结果,使用RecyclerView显示数据,实现刷新和加载更多的操作;
4、RecyclerView 子项长按、短按处理;

技术介绍

1、使用滚动选择器,选取时间,本来是想用日历控件的。。
2、使用SQLite存储计算结果
3、RecyclerView的使用
4、SmartRefreshLayout 实现刷新和加载
5、使用队列和栈,实现计算器
6、使用Calendar进行日期计算操作

编写环境

1、Android Studio 2.3.3
2、JDK 1.8

效果图

一、计算界面
在这里插入图片描述
二、计算器以及记录

注意:计算器的%用于求余数

注意:计算器进入维护
计算:5+12%5*2 时出现错误,目前进入维护,看官请仅参考思路
在这里插入图片描述

主要代码

(一)计算器

思路:
1、将数字和操作符分类监听
2、维护一个StringBuilder对象content用于存储计算的字符串
3、将“-”减号作为负号计算,遍历content,用队列存储数值和操作符
4、计算时,如遇加法,就将数值队列顶部元素加入到结果栈中,如遇优先级高的,就取结果栈顶元素与队列头部元素进行计算。然后计算结果加入栈中。最后取出结果栈中元素,累加得到最终结果。

计算器结果存在问题,最近没有时间,感兴趣可以自己先解决一下,大致就是直接的加减操作出现了问题;

问题已经解决,由于没有将数值队列的内容清空,导致计算结果少了一项。

numberStack.addAll(numbers);  //清理库存

计算逻辑:

            //计算逻辑
            while(!operators.isEmpty()) {
                String operator = operators.poll();
                float param1 = numberStack.isEmpty()?numbers.poll():numberStack.pop();
                float param2 = numbers.poll();

                if(isPrior(operator)) {
                    numberStack.add(calculateByOperator(param1,param2,operator));
                }else {
                    numberStack.add(param1);
                    numberStack.add(param2);
                }
            }

计算器活动代码:


import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;

import com.zhh.rent.R;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class CalculateActivity extends AppCompatActivity {

    TextView mEtContent;
    TextView mTvResult;
    ImageButton mIBtnBack;

    Button mBtn0, mBtn1, mBtn2, mBtn3, mBtn4, mBtn5, mBtn6, mBtn7, mBtn8, mBtn9;
    Button mBtnAdd, mBtnReduce, mBtnRide, mBtnDivide;
    Button mBtnClear, mBtnPoint, mBtnEqual, mBtnRemainder;

    StringBuilder content = new StringBuilder();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.calculate_activity);
        initView();
        btnClickListener();
    }

    private void initView() {
        mEtContent = findViewById(R.id.calculate_content);
        mTvResult = findViewById(R.id.calculate_result);

        content.append(mEtContent.getText().toString());

        mBtn0 = findViewById(R.id.number_zero);
        mBtn1 = findViewById(R.id.number_one);
        mBtn2 = findViewById(R.id.number_tow);
        mBtn3 = findViewById(R.id.number_three);
        mBtn4 = findViewById(R.id.number_four);
        mBtn5 = findViewById(R.id.number_five);
        mBtn6 = findViewById(R.id.number_six);
        mBtn7 = findViewById(R.id.number_seven);
        mBtn8 = findViewById(R.id.number_eight);
        mBtn9 = findViewById(R.id.number_nine);

        mBtnAdd = findViewById(R.id.operator_plus);
        mBtnReduce = findViewById(R.id.operator_reduce);
        mBtnRide = findViewById(R.id.operator_ride);
        mBtnDivide = findViewById(R.id.operator_divide);
        mBtnRemainder = findViewById(R.id.operator_remainder);

        mIBtnBack = findViewById(R.id.operator_back);
        mBtnClear = findViewById(R.id.operator_clear);
        mBtnPoint = findViewById(R.id.operator_point);
        mBtnEqual = findViewById(R.id.operator_equal);
    }

    private void btnClickListener() {
        //数字监听
        mBtn0.setOnClickListener(new numberListener());
        mBtn1.setOnClickListener(new numberListener());
        mBtn2.setOnClickListener(new numberListener());
        mBtn3.setOnClickListener(new numberListener());
        mBtn4.setOnClickListener(new numberListener());
        mBtn5.setOnClickListener(new numberListener());
        mBtn6.setOnClickListener(new numberListener());
        mBtn7.setOnClickListener(new numberListener());
        mBtn8.setOnClickListener(new numberListener());
        mBtn9.setOnClickListener(new numberListener());
        //加减乘除 取余
        mBtnAdd.setOnClickListener(new operatorListener());
        mBtnReduce.setOnClickListener(new operatorListener());
        mBtnRide.setOnClickListener(new operatorListener());
        mBtnDivide.setOnClickListener(new operatorListener());
        mBtnRemainder.setOnClickListener(new operatorListener());
        //功能键
        mIBtnBack.setOnClickListener(new toolListener());
        mBtnClear.setOnClickListener(new toolListener());
        mBtnPoint.setOnClickListener(new toolListener());
        mBtnEqual.setOnClickListener(new toolListener());
    }

    private class numberListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.number_zero:
                    addContent("0");
                    break;
                case R.id.number_one:
                    addContent("1");
                    break;
                case R.id.number_tow:
                    addContent("2");
                    break;
                case R.id.number_three:
                    addContent("3");
                    break;
                case R.id.number_four:
                    addContent("4");
                    break;
                case R.id.number_five:
                    addContent("5");
                    break;
                case R.id.number_six:
                    addContent("6");
                    break;
                case R.id.number_seven:
                    addContent("7");
                    break;
                case R.id.number_eight:
                    addContent("8");
                    break;
                case R.id.number_nine:
                    addContent("9");
                    break;
                default:
                    break;
            }
        }
    }

    private class operatorListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.operator_plus:
                    addContent("+");
                    break;
                case R.id.operator_reduce:
                    addContent("-");
                    break;
                case R.id.operator_ride:
                    addContent("×");
                    break;
                case R.id.operator_divide:
                    addContent("÷");
                    break;
                case R.id.operator_remainder:
                    addContent("%");
                    break;
            }
        }
    }

    private class toolListener implements View.OnClickListener {
        @Override
        public void onClick(View v) {
            switch (v.getId()) {
                case R.id.operator_clear:
                    clearContent();
                    break;
                case R.id.operator_back:
                    backContent();
                    break;
                case R.id.operator_equal:
                    getResult(true);
                    break;
                case R.id.operator_point:
                    addContent(".");
                    break;
            }
        }
    }

    private void clearContent() {
        if (content.length() != 0) content.delete(0, content.length());  //左闭右开
        mEtContent.setText("");
        mTvResult.setText("");
    }


    private void backContent() {
        if (content.length() > 0) content.deleteCharAt(content.length() - 1);  //参数是索引
        if (content.length() > 0) {
            String result = getResult(false);
            if (result != null) mTvResult.setText(result);
        }
        if (content.length() == 0) mTvResult.setText("");
        mEtContent.setText(content.toString());

    }

    private void addContent(String str) {
        if (content.length() == 0) {
            if (firstEnterJudgeToAdd(str)) content.append(str);
        } else {
            if (lastEnterJudgeToAdd(str)) content.append(str);
        }
        mEtContent.setText(content.toString());
        if (!isOperator(str)) mTvResult.setText(getResult(false));
    }

    private boolean isOperator(String str) {
        return str.equals("+") || str.equals("÷") || str.equals("×") || str.equals("=") || str.equals("%") || str.equals(".") || str.equals("-");
    }

    private boolean firstEnterJudgeToAdd(String str) {
        if (content.length() == 0) {
            switch (str) {
                case "-":
                    break;
                case ".":
                    content.append("0");
                    break;
                default:
                    if (isOperator(str)) return false;
                    break;
            }
        }
        return true;
    }

    private boolean lastEnterJudgeToAdd(String str) {
        boolean lastCharIsOperator = isOperator(String.valueOf(content.charAt(content.length() - 1)));
        if (lastCharIsOperator && isOperator(str)) {  //最后输入是操作符
            //并且不是第一个字符的时候替换
            if (content.length() != 1) content.replace(content.length() - 1, content.length(), str);
            return false;
        }
        return true;
    }

    private String getResult(boolean isEqual) {
        try {
            Queue<Float> numbers = new LinkedList<>();
            Queue<String> operators = new LinkedList<>();
            int startIndex = 0;
            String str;
            for (int index = 0; index < content.length(); index++) {
                str = String.valueOf(content.charAt(index));
                if (str.equals("-")) {
                    if (index != 0) {
                        numbers.add(Float.parseFloat(content.substring(startIndex, index)));
                        operators.add("+");
                        startIndex = index;
                    }
                    continue;
                }
                if (isOperator(str) && !str.equals(".")) {        //非最后字符时,遇操作符就分割
                    operators.add(str);
                    numbers.add(Float.parseFloat(content.substring(startIndex, index)));
                    startIndex = index + 1;
                }
                if (index == content.length() - 1) {                  //最后字符
                    if (isOperator(str) && !str.equals(".")) {      //有操作符分割
                        operators.add(str);
                        numbers.add(Float.parseFloat(content.substring(startIndex, index)));
                    }
                    numbers.add(Float.parseFloat(content.substring(startIndex)));   //无操作符全加入
                }
            }
            //这里写计算器计算逻辑
            return isEqual ? calculateByQueue(numbers, operators, true) : calculateByQueue(numbers, operators);
        } catch (ArithmeticException e) {
            Log.e("RentCalculateGet", e.getMessage());
            mTvResult.setText("错误");
            return "错误";
        } catch (Exception e) {
            Log.e("RentCalculateGet", e.getMessage());
            return "错误";
        }
    }

    private boolean isPrior(String str) {
        return (str.equals("÷") || str.equals("%") || str.equals("×"));
    }

    /**
     * 该算法,算漏了最后的输入,问题出加入队列时漏判了内容,已解决
     * 该算法未考虑优先级,改动队列无效,并不能解决优先级问题,例如8*2-14/7
     * 基本计算已经在方案二实现
     * @param numbers
     * @param operators
     * @return
     */
    private String calculateByQueue(Queue<Float> numbers, Queue<String> operators) {
        if (operators.size() == 0) {
            String onlyNumberResult = numbers.poll().toString();
            return onlyNumberResult.contains(".0") ? onlyNumberResult.replace(".0", "") : onlyNumberResult;
        }
        try {
            //方案二 先乘除后加减,合二为一
            Stack<Float> numberStack = new Stack<>();
            System.out.println("Numbers"+"队列" + numbers.toString());
            System.out.println("Numbers"+"操作队列" + operators.toString());

            //计算逻辑
            while(!operators.isEmpty()) {
                String operator = operators.poll();
                float param1 = numberStack.isEmpty()?numbers.poll():numberStack.pop();
                float param2 = numbers.poll();

                if(isPrior(operator)) {
                    numberStack.add(calculateByOperator(param1,param2,operator));
                }else {
                    numberStack.add(param1);
                    numberStack.add(param2);
                }
            }

            numberStack.addAll(numbers);  //清理库存
            Float calculateResult = 0.0f;
            System.out.println("Numbers"+"栈"+numberStack.toString());
            while (!numberStack.empty()) {
                Float f = numberStack.pop();
                calculateResult = calculateResult + f;
            }
            String result = calculateResult.toString();
            System.out.println("计算结果:"+result);
            return result.contains(".0") ? result.replace(".0", "") : result;
        } catch (Exception e) {
            System.out.println("RentCalculateByQueue"+ e.getMessage());
            return "错误";
        }
    }

    private String calculateByQueue(Queue<Float> numbers, Queue<String> operators, Boolean isEqual) {
        String result = calculateByQueue(numbers, operators);
        if (isEqual) {
            mTvResult.setText("");
            content.delete(0, content.length());
            if (!result.equals("错误")) {
                content.append(result.contains(".0") ? result.replace(".0", "") : result);
                mEtContent.setText(content);
            }
        }
        return result;
    }

    /* 运算符 + - × ÷ */
    private float calculateByOperator(Float param1, Float param2, String operator) {
        Float result = 0f;
        switch (operator) {
            case "+":
                result = param1 + param2;
                break;
            case "-":
                result = param1 - param2;
                break;
            case "×":
                result = param1 * param2;
                break;
            case "÷":
                result = param1 / param2;
                break;
            case "%":
                result = param1 % param2;
            default:
                break;
        }
        return result;
    }

}

布局文件:
布局使用的是线性布局,由于按键较多且比较整齐,表格布局也是不错的选择。
由于布局文件,内容过多,就不展示了,大致就是两个文本框,然后四行五列。摆放按钮就行了。后面会提供下载方式。

(二)月份计算

思路:完全可以当做数学加减法来计算,就是当前位不够,就向前借一位来凑。


    private String calculateDifferentByCalender(Date startTime,Date endTime){
        //使用Calendar来计算时间间隔,通过get方法获取月份时要加一
        Calendar startCalender = Calendar.getInstance();
        startCalender.setTime(startTime);
        Calendar endCalender = Calendar.getInstance();
        endCalender.setTime(endTime);

        //如果开始时间大于截止时间,退出返回空值
        if(startTime.getTime()>endTime.getTime()) return "";
        if(startTime.getTime()==endTime.getTime()) return "0月0天";

        int intervalYear=0,intervalMonth=0,intervalDay=0;
        int startYear,startMonth,startDay;
        int endYear,endMonth,endDay;

        startYear = startCalender.get(Calendar.YEAR);
        startMonth = startCalender.get(Calendar.MONTH)+1;  //获取月份不正常,要加1,因为Calender月份初始值为0
        startDay = startCalender.get(Calendar.DAY_OF_MONTH);

        endYear = endCalender.get(Calendar.YEAR);
        endMonth = endCalender.get(Calendar.MONTH)+1;  //获取月份不正常,要加1,因为Calender月份初始值为0
        endDay = endCalender.get(Calendar.DAY_OF_MONTH);

        intervalYear = endYear - startYear;       //endYear>=startYear 恒成立

        if(startMonth<=endMonth && startDay<=endDay){
            intervalMonth = endMonth - startMonth;
            intervalDay = endDay - startDay;
        } else if(startMonth<=endMonth && startDay>endDay){
            intervalMonth = endMonth-startMonth-1;             //开始日期大于截止日期,向前借一位
            int lastMonthDays = endMonth==1?31:getDay(endYear,endMonth-1);     //如果截止月份为一月,则前一个月就是31天,否则正常计算
            intervalDay = lastMonthDays - startDay + endDay;   //5月10 到 7月2号  6月有30天 间隔天=30-10+2
        } else if(startMonth>endMonth && startDay<=endDay){
            intervalYear -= 1;                                 //开始月份大于截止月份,代表前一年入住,年份减一,月份加12
            intervalMonth = endMonth + 12 - startMonth;
            intervalDay = endDay - startDay;
        } else if(startMonth>endMonth && startDay>endDay){     //最后一种情况,为方便计算,将条件写出
            intervalYear -= 1;                                  //开始月份大于截止月份,向前借一位
            intervalMonth = endMonth + 12 - startMonth - 1;             //开始日期大于截止日期,向前借一位
            int lastMonthDays = endMonth==1?31:getDay(endYear,endMonth-1);     //如果截止月份为一月,则前一个月就是31天,否则正常计算
            intervalDay = lastMonthDays - startDay + endDay;   //5月10 到 7月2号  6月有30天 间隔天=30-10+2
        }

        int sumMonth = intervalYear*12 + intervalMonth;

        return ""+sumMonth+"月"+intervalDay+"天";
    }

郑重声明

由于能力有限,本代码仅用于学习交流,计算结果仅供参考,不保证结果正确性。如有Bug请留言交流,近期应该有时间维护。

源码

(一)试用的APK
目标版本是Android 8 ,我使用Android运行的。apk下载地址如下:
Rent试用apk

APK下载地址:
链接: https://pan.baidu.com/s/1hd0vFXI4OIY6ytkJOUcyRg 
提取码: uj7p 

(二)Android源码
环境:Android Studio 2.3.3 JDK1.8
Rent源码

源码地址:
链接: https://pan.baidu.com/s/1cCWonoe6sB7uJBID9ehUaw 
提取码: gkfk

最后,最近在看《代码整洁之道》,虽然我目前技术不行,但是现阶段阅读还是能有不少收获的。书籍主张小而精的代码,主张通俗易懂的命名和结构。推荐大家看看。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值