Android - a magical calculator app

infix operation

        The infix operation defines two stacks, the number stack and the symbol stack; respectively store the numbers entered by the user (for example: 1, 2, 3) and the symbols (for example: +, -);
        the following video uses 1+2+3 /2*3%3 as an example; first input 1, then input +, by monitoring the operator click event, put them into the digital stack and symbol stack respectively, and then input 2 and +, that is, monitor +, and take out The top element of the symbol stack, to determine whether it is an initialization element, if not, take out the top element of the digital stack, and obtain the spliced ​​character as another arithmetic number; (the top element of the digital stack & (represents the top element of the symbol stack ) splicing strings) (1+2); after getting the result 3, push it into the number stack, and push the second + sign into the symbol stack for the next operation; and so on...

effect video

operation

Custom circular TextView

renderings

insert image description here

Create attr file

Change the style of the button by monitoring the gesture action of the control; that is, white when pressed, and orange when released

<resources>
    <declare-styleable name="SetCircle">
        <attr name="CircleColor" format="color"/>
        <attr name="SelectCircle" format="color"/>
    </declare-styleable>
</resources>

draw a circle


    protected void onDraw(Canvas canvas) {
    //判断手势动作,改变控件状态
        if (isSelect){
            CirclePaint.setColor( SelectCircle );
        }else {
            CirclePaint.setColor( CircleColor );
        }
        //设置填充方式
        CirclePaint.setStyle( Paint.Style.FILL );
        //设置抗锯齿
        CirclePaint.setAntiAlias( true );
        RectF rectF = new RectF();
        //设置半径,比较长宽,取最大值
        int radius = getMeasuredWidth() > getMeasuredHeight() ? getMeasuredWidth() : getMeasuredHeight();
        rectF.set(getPaddingLeft(),getPaddingTop(),radius-getPaddingRight(),radius-getPaddingBottom());
        //绘制圆弧
        canvas.drawArc(rectF,0,360,false,CirclePaint);
        super.onDraw(canvas);
    }

character splicing

The numbers input by the user are spliced ​​through StringBuilder, the reset button is judged at the end of the segment, and the number stack, symbol stack and the content of the spliced ​​string are all cleared;

private class NumOnClick implements View.OnClickListener{
        @Override
        public void onClick(View view) {
            switch (view.getId()){
                case R.id.Zero:
                    numBuilder.append('0');
                    break;
                case R.id.One:
                    numBuilder.append('1');
                    break;
                case R.id.Two:
                    numBuilder.append('2');
                    break;
                case R.id.Three:
                    numBuilder.append('3');
                    break;
                case R.id.Four:
                    numBuilder.append('4');
                    break;
                case R.id.Five:
                    numBuilder.append('5');
                    break;
                case R.id.Six:
                    numBuilder.append('6');
                    break;
                case R.id.Seven:
                    numBuilder.append('7');
                    break;
                case R.id.Eight:
                    numBuilder.append('8');
                    break;
                case R.id.Nine:
                    numBuilder.append('9');
                    break;
                case R.id.Point:
                    numBuilder.append('.');
                    break;
                case R.id.Reset:
                    isReset = true;
            }
            if (isReset){
                PopStack();
                numBuilder.delete(0,numBuilder.length());
                ResultBox.setText("0");
                operatorStack.push('#');
                isReset = false;
            }else {
                ResultBox.setText(numBuilder.toString());
            }

        }
    }

Empty stack elements

Empty the elements in the number stack and symbol stack

  private void PopStack(){
        while (numStack.isEmpty()){
            numStack.pop();
        }
        while (operatorStack.isEmpty()){
            operatorStack.pop();
        }
    }

operation execution

Gesture monitoring

Here we take the addition operator as an example, monitor the pressing and releasing, change the control style respectively, and pass in the corresponding operator for operation

   private class OperatorOnClick implements View.OnTouchListener{

        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) {
            boolean isPress = false;
            if (motionEvent.getAction() == MotionEvent.ACTION_DOWN){
                isPress = true;
            }
            switch (view.getId()){
                case R.id.Add:
                    if (isPress){
                        mAdd.IsSelect(true);
                        mAdd.setTextColor(getResources().getColor(R.color.normal));
                        StartOperation(ADD);
                    }else {
                        mAdd.IsSelect(false);
                        mAdd.setTextColor(getResources().getColor(R.color.select));
                    }
                    break;

Push && Pop

During initialization, push the symbol stack into the '#' symbol, which means the first execution, and no result operation is performed.

operatorStack.push('#');

    When running for the first time, the top element of the symbol stack is taken out, that is, '#'. If 1 and + are input, the formula cannot be formed at this time, because there is indeed another operand, that is, it is directly pushed into the stack, and the result is not performed. operation; then clear the concatenated string, because if 100 and + are entered, because the + sign is not displayed in the user interface, if it is not cleared, the characters entered later will be appended after it, for example, when 50 is entered, that is, no Clearing it to 10050 will cause disadvantages such as poor user experience and troublesome use;
  if you enter 100 and +, and then enter 50 and - to form a 100+50- formula, the first time no calculation is performed, as shown in the above explanation, the second time The input -, that is, take the top element of the symbol stack +, and the operands 100 and 50, and pass them into the EXEOperation() method to start the calculation result

   private void StartOperation(char symbol){
        char operator = operatorStack.pop();
        if (operator == EQUAL){
            operatorStack.push(symbol);
        } else if (operator == '#'){
            numStack.push(numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()));
            operatorStack.push(symbol);
            numBuilder.delete(0,numBuilder.length());
        }else {
            switch (operator){
                case ADD:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),ADD);
                    break;
                case SUB:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),SUB);
                    break;
                case MULTIPLY:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),MULTIPLY);
                    break;
                case DIVISION:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),DIVISION);
                    break;
                case MOD:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()),MOD);
                    break;
                case EQUAL:
                    EXEOperation(numStack.pop(),numBuilder.toString().isEmpty()?0:Double.parseDouble(numBuilder.toString()));
                    break;
            }
        }
    }

Operation result

  The three parameters are the first operand, another operand, and the top element of the symbol stack, the symbol is judged, and the result is calculated, and then the result is pushed into the stack and the second operator is pushed to match Stack;
  the key is to judge the equal key:
    1: For example, enter the formula 1+1-, monitor the second operator to get the previous result, and then enter numbers and symbols to get the previous result...
    2: For example Enter the formula 1+1=, at this time, the equal symbol is not monitored, and the operation cannot be completed. The solution is to not push the equal to the symbol stack, and directly push the result into the stack, which is equivalent to the first step to complete the operation.

Decimal place judgment

Substring interception is performed on the result string to determine whether there are decimal places after the decimal point. Because it is of double type, there are decimal places by default. For example:
(1) 1.0, omit the 0 after the decimal point and output 0 directly;
(2) 1.05, do not omit the decimal place and output directly

 //判断小数位之后是否有数字
        if (str.substring(str.indexOf('.') + 1, str.length() - 1).isEmpty()) {
            str = str.substring(0, str.indexOf('.'));
        }

Operation code

    private void EXEOperation(double front,double rear,char operator) {
        double result = 0;
        String str;
        /**
         * 对连续点击运算符,而运算数字并未符合标准时进行判断
         * 例如:12+
         * 此时12和+分别进栈,此时若再点击运算符+,则无法进行运算,因为rear运算数为空*/
        switch (operator) {
            case ADD:
                result = front + rear;
                break;
            case SUB:
                result = front - rear;
                break;
            case MULTIPLY:
                result = front * rear;
                break;
            case DIVISION:
                result = front / rear;
                break;
            case MOD:
                result = front < rear ? front :front % rear;
                break;
        }
        numStack.push(result);
        if (isReturn){
            operatorStack.push(EQUAL);
        }else {
            operatorStack.push(operator);
            isReturn = false;
        }
        str = String.valueOf(result);
        //判断小数位之后是否有数字
        if (str.substring(str.indexOf('.') + 1, str.length() - 1).isEmpty()) {
            str = str.substring(0, str.indexOf('.'));
        }
        ResultBox.setText(str);
        //前运算符清空,为后运算符输入做准备
        numBuilder.delete(0,numBuilder.length());
    }

arbitrary base conversion

By inputting decimal numbers, convert them into corresponding binary, octal, and hexadecimal numbers respectively

effect video

conversion base

base conversion

Because multiple bases need to be converted separately, the length of the array cannot be judged, that is, the first element of each number is used as the address for storing the length of the array

   private int[] Conversion(int num,int binary){
     int[] remainder = new int[255];
     int count = 1;
     do {
         remainder[count++] = num%binary;
         num /= binary;
     } while (num != 0);
     remainder[0] = count;
     return remainder;
    }

result inversion

By inverting the parsed hexadecimal array, because hexadecimal 10-A, 11-B..., it needs to be judged, and then use string concatenation, and finally return a result string

    private String Inversion(int[] array){
            StringBuilder builder = new StringBuilder();
        for (int i = array[0]-1; i >=1 ; i--) {
            if (array[i] == 10){
                builder.append("A");
            }else if (array[i] == 11){
                builder.append("B");
            }else if (array[i] == 12){
                builder.append("C");
            }else if (array[i] == 13){
                builder.append("D");
            }else if (array[i] == 14){
                builder.append("E");
            }else if (array[i] == 15){
                builder.append("F");
            }else {
                builder.append(array[i]);
            }
        }
        return builder.toString();
    }

result returned

int num = Integer.parseInt(ResultBox.getText().toString());
Binary_2.setText(Inversion(Conversion(num,2)));
Binary_8.setText(Inversion(Conversion(num,8)));
Binary_10.setText(Inversion(Conversion(num,10)));
Binary_16.setText(Inversion(Conversion(num,16)));

Guess you like

Origin blog.csdn.net/News53231323/article/details/123234328