Una increíble aplicación de calculadora.
operación infija
La operación de infijos define dos pilas, la pila de números y la pila de símbolos; almacenan respectivamente los números ingresados por el usuario (por ejemplo: 1, 2, 3) y los símbolos (por ejemplo: +, -);
el siguiente video usa 1 +2+3 /2*3%3 como ejemplo; primero ingrese 1, luego ingrese +, al monitorear el evento de clic del operador, colóquelos en la pila digital y la pila de símbolos respectivamente, y luego ingrese 2 y +, es decir, monitor +, y saque el elemento superior de la pila de símbolos, para determinar si es un elemento de inicialización, si no, saque el elemento superior de la pila digital, y obtenga el carácter empalmado como otro número aritmético; (el elemento superior de la pila digital & (representa el elemento superior de la pila de símbolos) cadenas de empalme) (1+2); después de obtener el resultado 3, introdúzcalo en la pila de números y presione el segundo signo + en la pila de símbolos para la siguiente operación, y así sucesivamente...
efecto de vídeo
operación
TextView circular personalizado
representaciones
Crear archivo attr
Cambie el estilo del botón al monitorear la acción del gesto del control; es decir, blanco cuando se presiona y naranja cuando se suelta
<resources>
<declare-styleable name="SetCircle">
<attr name="CircleColor" format="color"/>
<attr name="SelectCircle" format="color"/>
</declare-styleable>
</resources>
dibuja un circulo
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);
}
empalme de personajes
Los números ingresados por el usuario se empalman a través de StringBuilder, el botón de reinicio se juzga al final del segmento, y la pila de números, la pila de símbolos y el contenido de la cadena empalmada se borran;
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());
}
}
}
Elementos de pila vacíos
Vaciar los elementos en la pila de números y la pila de símbolos
private void PopStack(){
while (numStack.isEmpty()){
numStack.pop();
}
while (operatorStack.isEmpty()){
operatorStack.pop();
}
}
ejecución de la operación
Monitoreo de gestos
Aquí tomamos el operador de suma como ejemplo, monitoreamos la presión y la liberación, cambiamos el estilo de control respectivamente y pasamos el operador correspondiente para la operación.
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;
Empujar y hacer estallar
Durante la inicialización, inserte la pila de símbolos en el símbolo '#', lo que significa la primera ejecución y no se realiza ninguna operación de resultado.
operatorStack.push('#');
Cuando se ejecuta por primera vez, se elimina el elemento superior de la pila de símbolos, es decir, '#'. Si se ingresan 1 y +, la fórmula no se puede formar en este momento, porque de hecho hay otro operando, es decir , se inserta directamente en la pila y el resultado no se realiza.Operación, luego borre la cadena concatenada, porque si se ingresan 100 y +, porque el signo + no se muestra en la interfaz de usuario, si no se borra, los caracteres ingresados más tarde se agregarán después, por ejemplo, cuando se ingresa 50, es decir, no borrarlo en 10050 causará desventajas como una mala experiencia de usuario y un uso problemático;
si ingresa 100 y +, y luego ingresa 50 y - para formar una fórmula 100+50-, la primera vez que no se realiza ningún cálculo, como se muestra en la explicación anterior, la segunda vez La entrada -, es decir, toma el elemento superior de la pila de símbolos +, y los operandos 100 y 50 y páselos al método EXEOperation() para iniciar el resultado del cálculo
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;
}
}
}
resultado de la operación
Los tres parámetros son el primer operando, otro operando y el elemento superior de la pila de símbolos, se juzga el símbolo y se calcula el resultado, y luego el resultado se empuja a la pila y el segundo operador se empuja para que coincida con Stack;
la clave es juzgar la tecla igual:
1: Por ejemplo, ingrese la fórmula 1+1-, controle el segundo operador para obtener el resultado anterior y luego ingrese números y símbolos para obtener el resultado anterior...
2: Por ejemplo Ingrese la fórmula 1 + 1 =, en este momento, el símbolo igual no se controla y la operación no se puede completar. La solución es no empujar el igual a la pila de símbolos, y empujar directamente el resultado a la pila, que es equivalente al primer paso para completar la operación.
Juicio de lugar decimal
La interceptación de subcadena se realiza en la cadena de resultado para determinar si hay lugares decimales después del punto decimal. Debido a que es de tipo doble, hay lugares decimales de forma predeterminada. Por ejemplo:
(1) 1.0, omita el 0 después del punto decimal y genere 0 directamente;
(2) 1.05, no omita el lugar decimal y genere directamente
//判断小数位之后是否有数字
if (str.substring(str.indexOf('.') + 1, str.length() - 1).isEmpty()) {
str = str.substring(0, str.indexOf('.'));
}
Código de operación
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());
}
conversión de base arbitraria
Al ingresar números decimales, conviértalos en números binarios, octales y hexadecimales correspondientes, respectivamente
efecto de vídeo
base de conversión
conversión básica
Debido a que varias bases deben convertirse por separado, no se puede juzgar la longitud de la matriz, es decir, el primer elemento de cada número se usa como la dirección para almacenar la longitud de la matriz.
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;
}
inversión de resultados
Al invertir la matriz hexadecimal analizada, porque el hexadecimal 10-A, 11-B..., debe juzgarse y luego usar la concatenación de cadenas y finalmente devolver una cadena de resultado
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();
}
resultado devuelto
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)));