安卓开发学习8-仿简单计算器
目录
1 界面分析
2 逻辑分析
3 实现
3.1 创建values,包括strings和dimens
3.2 实现界面布局
3.3 实现代码逻辑
3.4 简单演示
1 界面分析
整体布局:线性垂直布局LinearLayout。
垂直滚动布局(防止布局超出手机边界)+线性垂直布局(存放控件)。
两个文本显示TextView和一个6*4的栅格布局GridLayout。
栅格布局中有的显示文字打不出来,使用图像显示按钮ImageButton。
2 逻辑分析
- 如果直接点击小数点,显示0.,且小数点只能添加一次。如果一直点0,直接显示0,避免出现0.0.、025、.25等情况。
- 不点击运算符,数字字符一直组合。且输入字符显示在文本显示2位置。
- 点击运算符。如果第一个数字字符,则第一个数字字符直接零。如果没有第二个数字,则运算符一直替换,如果有第二个数字,则先计算出来结果,结果加上输入的运算符。
- 点击等号,计算出结果。如果直接点击数字,将会开始新的运算。
- 如果一直点击等号,则循环进行计算。如果点击其它运算符号,则执行其它计算。
- 如果点击退格,含有等号,清空数据。不含有等号,退格删除第一个数或第二个数,直至没有位数变为0。
- 点击CE,含有等号,清空数据。不含有等号,清空当前输入数字。
- 点击C,清空数据。
- 如果点击百分号,平方,平方根、正负号,会对当前数据进行操作。例如显示第一个数,对一个数进行计算,显示第二个数,对第二个数进行计算,显示结果,对结果进行计算。
3 实现
3.1 创建values,包括strings和dimens
strings
<resources><string name="app_name">"简单计算器"</string><string name="hello">"Hello World!"</string><string name="one">"1"</string><string name="two">"2"</string><string name="three">"3"</string><string name="four">"4"</string><string name="five">"5"</string><string name="six">"6"</string><string name="seven">"7"</string><string name="eight">"8"</string><string name="nine">"9"</string><string name="zero">"0"</string><string name="dot">"."</string><string name="plus">"+"</string><string name="minus">"-"</string><string name="multiply">"×"</string><string name="divide">"÷"</string><string name="equal">"="</string><string name="percent">"%"</string><string name="reciprocal">"1/x"</string><string name="square">"x^2"</string><string name="plus_minus">"+/-"</string><string name="sqrt">"平方根"</string><string name="delete">"删除"</string><string name="clear">"C"</string><string name="clear_entry">"CE"</string>
</resources>
dimens
<?xml version="1.0" encoding="utf-8"?>
<resources><dimen name="button_font_size"> 30sp </dimen><dimen name="button_height_size"> 70sp </dimen>
</resources>
3.2 实现界面布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:id="@+id/main"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"android:padding="20dp"><!-- 添加垂直滚动布局--><ScrollViewandroid:layout_width="match_parent"android:layout_height="wrap_content"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tv_calculate"android:layout_width="match_parent"android:layout_height="wrap_content"android:textSize="40sp"android:textColor="@color/black"android:lines="2"android:gravity="right|bottom"/><TextViewandroid:id="@+id/tv_result"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/zero"android:textSize="70sp"android:textColor="@color/black"android:gravity="right|bottom"/><!--4*6布局--><GridLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:columnCount="4"android:rowCount="6"><Buttonandroid:id="@+id/btn_percent"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_row="0"android:layout_columnWeight="1"android:text="@string/percent"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_clear_entry"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/clear_entry"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_clear"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/clear"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><ImageButtonandroid:id="@+id/btn_delete"android:contentDescription="@string/delete"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:src="@drawable/delete"android:scaleType="fitCenter"/><Buttonandroid:id="@+id/btn_reciprocal"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/reciprocal"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_square"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/square"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><ImageButtonandroid:id="@+id/btn_sqrt"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:contentDescription="@string/sqrt"android:src="@drawable/sqrt"android:scaleType="fitCenter"android:padding="12dp"/><Buttonandroid:id="@+id/btn_divide"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/divide"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_seven"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/seven"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_eight"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/eight"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_nine"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/nine"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_multiply"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/multiply"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_four"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/four"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_five"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/five"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_six"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/six"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_minus"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/minus"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_one"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/one"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_two"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/two"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_three"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/three"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_plus"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/plus"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_plus_minus"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/plus_minus"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_zero"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/zero"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_dot"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/dot"android:textSize="@dimen/button_font_size"android:textColor="@color/black"/><Buttonandroid:id="@+id/btn_equal"android:layout_width="0dp"android:layout_height="@dimen/button_height_size"android:layout_columnWeight="1"android:text="@string/equal"android:textSize="@dimen/button_font_size"android:textColor="@color/white"android:background="@color/purple_500" /></GridLayout></LinearLayout></ScrollView></LinearLayout>
3.3 实现代码逻辑
简单按钮捕获逻辑说明:
直接监听此界面Activity所有按钮,根据按钮id判断是哪个按钮发出了点击事件。
计算过程中主要有四个全局变量:
firstNum:第一个运算数
secondNum:第二个运算数
operateSymbol:存储加减乘除运算符
otherSymbol:存储其它运算符,包括平方,百分号,平方根等。
主要函数:
onClick(View v):捕获按钮点击事件,执行对应的逻辑计算。
numberOperate(View v):获取按钮数字。
dealNums(String,String):组合数字。
fourOperate(View v):处理加减乘除计算。
equalOperate():处理等号计算逻辑。
otherOperate(View v):其它运算符处理逻辑。
calculateOther(String symbol,String current):实现其他运算符运算逻辑。
处理删除相关函数:
clear():清空所有显示,恢复默认显示0。
CEOperate():清空当前输入。
deleteOperate():退格删除。
显示函数:
showCalculateText(String):计算过程文本显示。
showResultText(String):计算结果文本显示。
一些功能函数:
数转文本(String):String.valueOf(Double)
文本转小数(Double):Double.parseDouble(String)
返回文本保留(String):subString(int begin,int end)
文本比较(bool):equal(String compareText)
文本包含(bool):contains(String text)
package com.example.linearlayout;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.TextView;import androidx.appcompat.app.AppCompatActivity;public class CalculatorActivity extends AppCompatActivity implements View.OnClickListener{//全局变量//第一个数private String firstNum="";//第二个数private String secondNum="";//结果private String resultNum="";//加减乘除运算符private String operatorSymbol="";//其它功能运算符private String otherSymbol = "";//控件//文本显示private TextView tv_calculate;private TextView tv_result;//数字键private Button btn_one;private Button btn_two;private Button btn_three;private Button btn_four;private Button btn_five;private Button btn_six;private Button btn_seven;private Button btn_eight;private Button btn_nine;private Button btn_zero;//小数点private Button btn_dot;//运算符private Button btn_plus;private Button btn_minus;private Button btn_multiply;private Button btn_divide;private Button btn_equal;private Button btn_percent;private Button btn_reciprocal;private Button btn_square;private Button btn_plus_minus;private ImageButton btn_sqrt;//清除键private ImageButton btn_delete;private Button btn_clear;private Button btn_clear_error;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_calculator);//获取控件//获取文本显示控件tv_calculate = findViewById(R.id.tv_calculate);tv_result = findViewById(R.id.tv_result);//获取所有按钮控件btn_one = findViewById(R.id.btn_one);btn_two = findViewById(R.id.btn_two);btn_three = findViewById(R.id.btn_three);btn_four = findViewById(R.id.btn_four);btn_five = findViewById(R.id.btn_five);btn_six = findViewById(R.id.btn_six);btn_seven = findViewById(R.id.btn_seven);btn_eight = findViewById(R.id.btn_eight);btn_nine = findViewById(R.id.btn_nine);btn_zero = findViewById(R.id.btn_zero);btn_dot = findViewById(R.id.btn_dot);btn_plus = findViewById(R.id.btn_plus);btn_minus = findViewById(R.id.btn_minus);btn_multiply = findViewById(R.id.btn_multiply);btn_divide = findViewById(R.id.btn_divide);btn_equal = findViewById(R.id.btn_equal);btn_percent = findViewById(R.id.btn_percent);btn_reciprocal = findViewById(R.id.btn_reciprocal);btn_square = findViewById(R.id.btn_square);btn_plus_minus = findViewById(R.id.btn_plus_minus);btn_sqrt = findViewById(R.id.btn_sqrt);btn_delete = findViewById(R.id.btn_delete);btn_clear = findViewById(R.id.btn_clear);btn_clear_error = findViewById(R.id.btn_clear_entry);//绑定监听器btn_one.setOnClickListener(this);btn_two.setOnClickListener(this);btn_three.setOnClickListener(this);btn_four.setOnClickListener(this);btn_five.setOnClickListener(this);btn_six.setOnClickListener(this);btn_seven.setOnClickListener(this);btn_eight.setOnClickListener(this);btn_nine.setOnClickListener(this);btn_zero.setOnClickListener(this);btn_dot.setOnClickListener(this);btn_plus.setOnClickListener(this);btn_minus.setOnClickListener(this);btn_multiply.setOnClickListener(this);btn_divide.setOnClickListener(this);btn_equal.setOnClickListener(this);btn_percent.setOnClickListener(this);btn_reciprocal.setOnClickListener(this);btn_square.setOnClickListener(this);btn_plus_minus.setOnClickListener(this);btn_sqrt.setOnClickListener(this);btn_delete.setOnClickListener(this);btn_clear.setOnClickListener(this);btn_clear_error.setOnClickListener(this);}@Override//按键接收public void onClick(View v) {//点了数字按钮if(v.getId() == R.id.btn_zero ||v.getId() == R.id.btn_one ||v.getId() == R.id.btn_two ||v.getId() == R.id.btn_three ||v.getId() == R.id.btn_four ||v.getId() == R.id.btn_five ||v.getId() == R.id.btn_six ||v.getId() == R.id.btn_seven ||v.getId() == R.id.btn_eight ||v.getId() == R.id.btn_nine ){numberOperate(v);}//点了小数点按钮else if(v.getId() == R.id.btn_dot){dotOperate();}//点了加减乘除按钮else if(v.getId() == R.id.btn_plus ||v.getId() == R.id.btn_minus ||v.getId() == R.id.btn_multiply ||v.getId() == R.id.btn_divide){fourOperate(v);}//点了等号按钮else if(v.getId() == R.id.btn_equal){equalOperate();}//点了退格按钮else if(v.getId() == R.id.btn_delete){deleteOperate();}//点了清空按钮else if(v.getId() == R.id.btn_clear){//清空计算clear();}//点了清空输入按钮else if(v.getId() == R.id.btn_clear_entry){CEOPerate();}//点了其它计算按钮 百分比 取倒数 平方 开平方根 正负号else if(v.getId() == R.id.btn_percent ||v.getId() == R.id.btn_reciprocal ||v.getId() == R.id.btn_square ||v.getId() == R.id.btn_sqrt ||v.getId() == R.id.btn_plus_minus){otherOperate(v);}}//其它功能操作计算private void otherOperate(View v) {//如果没有数,退出程序if(firstNum.isEmpty()){return;}//由于开平方根是ImageButton,需要手动添加符号if(v.getId() == R.id.btn_sqrt){otherSymbol = "√";}else{//其它 取出运算符otherSymbol = ((Button) v).getText().toString();}//如果有等号if(tv_calculate.getText().toString().contains("=")){//清空符号和第二个数operatorSymbol = "";secondNum = "";if(otherSymbol.equals("+/-")){//显示数值showCalculateText("(" + calculateOther(otherSymbol,firstNum) + ")");}else{showCalculateText("(" + otherSymbol + firstNum + ")");}//对结果进行计算,传递参数(结果参数已经传递)//清空加减操作运算符,避免进入下面的操作firstNum = calculateOther(otherSymbol,firstNum);showResultText(firstNum);}//如果没有加减运算符,对第一个数据进行计算else if(operatorSymbol.isEmpty()){if(otherSymbol.equals("+/-")){//显示数值showCalculateText("(" + calculateOther(otherSymbol,firstNum) + ")");}else{showCalculateText("(" + otherSymbol + firstNum + ")");}//对第一个数进行计算且显示在计算区域firstNum = calculateOther(otherSymbol,firstNum);showResultText(firstNum);}//如果有加减运算符且没有等号else if(!operatorSymbol.isEmpty() && !tv_calculate.getText().toString().contains("=")){//如果有加减运算符,但是没有第二个数,则默认第二数等于第一个数if(secondNum.isEmpty()){secondNum = firstNum;}if(otherSymbol.equals("+/-")){//显示数值showCalculateText(firstNum + operatorSymbol+"(" + calculateOther(otherSymbol,secondNum) + ")");}else{//显示数值showCalculateText(firstNum + operatorSymbol+"(" + otherSymbol + secondNum + ")");}//对第二个数进行计算secondNum = calculateOther(otherSymbol,secondNum);showResultText(secondNum);}}//数字键操作private void numberOperate(View v){//如果计算显示文本中含有等号,则执行清空操作if(tv_calculate.getText().toString().contains("=")){clear();}//取出符号String code = ((Button)v).getText().toString();//处理数字符号if(operatorSymbol.isEmpty()){firstNum = dealNums(code,firstNum);}else{secondNum = dealNums(code,secondNum);}}//小数点操作private void dotOperate(){//如果计算显示文本中含有等号,则执行清空操作if(tv_calculate.getText().toString().contains("=")){clear();}//处理小数点if(operatorSymbol.isEmpty()){firstNum = dealDot(firstNum);}else{secondNum = dealDot(secondNum);}}//四则运算操作private void fourOperate(View v){//获取运算符//1.如果第一个数字为空,则第一个数字直接为0,加上运算符//2.如果第二的数字为空,则不进入计算,只更改运算符//3.如果第二个数字不为空,则进入计算,将上次的数据运算完毕,再将计算的结果和这次接收运算符号显示刷新//如果上次计算中含有等号,则需要将第二个数清空,避免直接进入条件3,多进行一次等号叠加计算操作,导致误差。if(tv_calculate.getText().toString().contains("=")){secondNum = "";}if(firstNum.isEmpty()){firstNum = "0";operatorSymbol = ((Button)v).getText().toString();showCalculateText(firstNum + operatorSymbol);}else if(!firstNum.isEmpty() && secondNum.isEmpty()){operatorSymbol = ((Button)v).getText().toString();showCalculateText(firstNum + operatorSymbol);}else if(!secondNum.isEmpty()){//先进行四则运算resultNum = calculateNum(operatorSymbol,firstNum,secondNum);//存储结果,删除清空运算符,数据2和结果initValues();//再获取刚刚点击的符号operatorSymbol = ((Button)v).getText().toString();//显示计算结果和符号showCalculateText(firstNum + operatorSymbol);}}//等号运算符操作private void equalOperate(){//如果第一个数字为空,直接输入等号,显示0if(firstNum.isEmpty()){showCalculateText("0");}//如果运算符为空或者第二个数为空,直接显示第一个数else if(operatorSymbol.isEmpty() || secondNum.isEmpty()){showCalculateText(firstNum);}//如果都不为空,直接点等号,则按照运算符,循环计算else{//如果是等号,显示数据和运算符以及等号showCalculateText(firstNum + operatorSymbol + secondNum + "=");//进行四则运算,接收运算结果resultNum = calculateNum(operatorSymbol,firstNum,secondNum);//不执行清空操作,只传递运算结果,方便继续按下等号执行计算firstNum = resultNum;}}private void deleteOperate(){//退格删除操作//如果计算显示文本中含有等号,则执行清空操作if(tv_calculate.getText().toString().contains("=")){clear();}if(operatorSymbol.isEmpty()){firstNum = deleteNum(firstNum);}else{secondNum = deleteNum(secondNum);}}//功能函数//清空输入操作private void CEOPerate() {//计算文本中含有等号,则按下CE键执行清空操作if(tv_calculate.getText().toString().contains("=")){clear();}else{//清空输入clearEntry();}}//计算完毕刷新数据private void initValues() {firstNum = resultNum;operatorSymbol = "";secondNum = "";resultNum = "";showCalculateText(firstNum + operatorSymbol);}//显示数字private String dealNums(String code,String currentNum) {//如果当前空,且输入为0,则显示零,避免出现0000if((currentNum.isEmpty() || currentNum.equals("0")) && code.equals("0")){currentNum = "";showResultText("0");}else{currentNum = currentNum + code;showResultText(currentNum);}return currentNum;}//显示小数点private String dealDot(String currentNum) {if(!currentNum.contains(".")){//如果为空,点小数点直接变成0.if(currentNum.isEmpty()){currentNum = "0.";}else{currentNum = currentNum + ".";}showResultText(currentNum);}return currentNum;}//显示计算文本,包括数字、运算符private void showCalculateText(String calculateText) {tv_calculate.setText(calculateText);}//显示结果文本private void showResultText(String resultText){tv_result.setText(resultText);}//退格操作private String deleteNum(String textNum) {if(textNum.length()-1 > 0){textNum = textNum.substring(0,textNum.length()-1);showResultText(textNum);}else if(textNum.length()-1 == 0){textNum = "";showResultText("0");}return textNum;}//清空输入private void clearEntry() {if(operatorSymbol.isEmpty()){firstNum = "";}else{secondNum = "";}tv_result.setText("0");}//清空显示private void clear() {firstNum = "";secondNum = "";resultNum = "";operatorSymbol = "";tv_calculate.setText("");tv_result.setText(R.string.zero);}//加减惩处运算private String calculateNum(String currentSymbol, String num1, String num2) {double result = 0.00;if(currentSymbol.equals("+")){result = Double.parseDouble(num1) + Double.parseDouble(num2);}else if(currentSymbol.equals("-")){result = Double.parseDouble(num1) - Double.parseDouble(num2);}else if(currentSymbol.equals("×")){result = Double.parseDouble(num1) * Double.parseDouble(num2);}else if(currentSymbol.equals("÷")){result = Double.parseDouble(num1) / Double.parseDouble(num2);}else{resultNum = "error";}//显示运算结果tv_result.setText(String.valueOf(result));return String.valueOf(result);}//其它运算private String calculateOther(String symbol,String currentText){String result = "";//取百分号if(symbol.equals("%")){result = String.valueOf(Double.parseDouble(currentText) / 100);}//取倒数else if(symbol.equals("1/x")){result = String.valueOf(1 / Double.parseDouble(currentText));}//取平方else if(symbol.equals("x^2")){result = String.valueOf(Math.pow(Double.parseDouble(currentText),2));}//开平方根else if(symbol.equals("√")){if(Double.parseDouble(currentText) < 0){result = "无效输入";}else{result = String.valueOf(Math.sqrt(Double.parseDouble(currentText)));}}//正负号替换else if(symbol.equals("+/-")){if(Double.parseDouble(currentText) != 0){result = String.valueOf(Double.parseDouble(currentText)*(-1));}else{result = String.valueOf(Double.parseDouble(currentText));}}//返回值return result;}}
3.4 简单演示