Android简单实现计算器功能 本文实例为大家分享了Android简单实现计算器的具体代码,供大家参考,具体内容如下 一.UI布局及代码 页面效果 布局代码 ?xml version=1.0 encoding=utf-8? LinearLayout xmlns:android=http://schemas.android.com/apk/res/android android:layout_width
本文实例为大家分享了Android简单实现计算器的具体代码,供大家参考,具体内容如下
一、UI布局及代码
- 页面效果
- 布局代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:weightSum="8">
<TextView
android:layout_width="match_parent"
android:layout_height="0dp"
android:id="@+id/text_view"
android:layout_weight="2"
android:textSize="70dp"
android:gravity="right|bottom"
android:maxLines="2" />
<TextView
android:id="@+id/result_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="right|bottom"
android:maxLines="1"
android:textSize="65dp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="5">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_ac"
android:layout_weight="1"
android:text="AC"
android:background="#ff0000"
android:textColor="#000"
android:textSize="20dp"
android:layout_margin="5dp" />
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_left"
android:layout_weight="1"
android:text="("
android:background="#fff"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_right"
android:layout_weight="1"
android:text=")"
android:background="#fff"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_divide"
android:layout_weight="1"
android:text="/"
android:background="#fffaf0"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_del"
android:layout_weight="1"
android:text="DEL"
android:background="#808a87"
android:textColor="#000"
android:textSize="15dp"
android:layout_margin="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_7"
android:layout_weight="1"
android:text="7"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_8"
android:layout_weight="1"
android:text="8"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_9"
android:layout_weight="1"
android:text="9"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_mult"
android:layout_weight="1"
android:text="*"
android:background="#fffaf0"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_4"
android:layout_weight="1"
android:text="4"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_5"
android:layout_weight="1"
android:text="5"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_6"
android:layout_weight="1"
android:text="6"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_add"
android:layout_weight="1"
android:text="+"
android:background="#fffaf0"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_1"
android:layout_weight="1"
android:text="1"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_2"
android:layout_weight="1"
android:text="2"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_3"
android:layout_weight="1"
android:text="3"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_minus"
android:layout_weight="1"
android:text="-"
android:background="#fffaf0"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="horizontal"
android:weightSum="4">
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_0"
android:layout_weight="2"
android:text="0"
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_dot"
android:layout_weight="1"
android:text="."
android:textColor="#000"
android:textSize="30dp"
android:layout_margin="5dp"/>
<Button
android:layout_width="0dp"
android:layout_height="match_parent"
android:id="@+id/button_result"
android:layout_weight="1"
android:text="="
android:background="#ff6347"
android:textColor="#fff"
android:textSize="30dp"
android:layout_margin="5dp"/>
</LinearLayout>
</LinearLayout>
- 解析
1、布局使用LinearLayout布局,android:orientation="vertical"指定垂直布局,从上至下依次是表达式显示框,结果显示框以及五行按钮,并指定总权重方便控制显示。
2、文本框TextView使用android:gravity="right|bottom"指定其从右下开始显示内容。
3、在按钮上,使用android:background="#ff0000"指定按钮背景颜色,使用android:layout_margin="5dp"控制偏移,使其不会过于紧凑。(关于按钮背景颜色无法设置,可在res//values//themes.xml文件下将代码<style name="Theme.Calculation" parent="Theme.MaterialComponents.DayNight.DarkActionBar.">
改为<style name="Theme.Calculation" parent="Theme.MaterialComponents.DayNight.DarkActionBar.Bridge">)
二、计算器逻辑设计
- 代码部分
package com.example.calculation;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.TypedValue;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import java.math.BigDecimal;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private final StringBuilder sb = new StringBuilder();//用于表达式的输入
private String expression = "";//最终表达式的确定
private String result = "";//计算结果
private boolean isHasDot = false;//是否有小数点
private final Stack<Boolean> dotStack = new Stack<>();
//用栈存储每一个数字是否有小数点
private boolean isZero = false;//是否是数字零
private final Stack<Boolean> zeroStack = new Stack<>();
private int leftNum = 0;//左括号数量
private int rightNum = 0;//右括号数量
private TextView textView;
private TextView result_view;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.text_view);
textView.setAutoSizeTextTypeUniformWithConfiguration(4, 70, 10, TypedValue.COMPLEX_UNIT_DIP);
//将显示框设置为根据行数自动缩小
result_view = (TextView) findViewById(R.id.result_view);
result_view.setAutoSizeTextTypeUniformWithConfiguration(4, 70, 10, TypedValue.COMPLEX_UNIT_DIP);
Button button1 = (Button) findViewById(R.id.button_1);
button1.setOnClickListener(this);
Button button2 = (Button) findViewById(R.id.button_2);
button2.setOnClickListener(this);
Button button3 = (Button) findViewById(R.id.button_3);
button3.setOnClickListener(this);
Button button4 = (Button) findViewById(R.id.button_4);
button4.setOnClickListener(this);
Button button5 = (Button) findViewById(R.id.button_5);
button5.setOnClickListener(this);
Button button6 = (Button) findViewById(R.id.button_6);
button6.setOnClickListener(this);
Button button7 = (Button) findViewById(R.id.button_7);
button7.setOnClickListener(this);
Button button8 = (Button) findViewById(R.id.button_8);
button8.setOnClickListener(this);
Button button9 = (Button) findViewById(R.id.button_9);
button9.setOnClickListener(this);
Button button0 = (Button) findViewById(R.id.button_0);
button0.setOnClickListener(this);
Button buttondot = (Button) findViewById(R.id.button_dot);
buttondot.setOnClickListener(this);
Button buttonadd = (Button) findViewById(R.id.button_add);
buttonadd.setOnClickListener(this);
Button buttonminus = (Button) findViewById(R.id.button_minus);
buttonminus.setOnClickListener(this);
Button buttonmult = (Button) findViewById(R.id.button_mult);
buttonmult.setOnClickListener(this);
Button buttondivide = (Button) findViewById(R.id.button_divide);
buttondivide.setOnClickListener(this);
Button buttonac = (Button) findViewById(R.id.button_ac);
buttonac.setOnClickListener(this);
Button buttondel = (Button) findViewById(R.id.button_del);
buttondel.setOnClickListener(this);
Button buttonleft = (Button) findViewById(R.id.button_left);
buttonleft.setOnClickListener(this);
Button buttonright = (Button) findViewById(R.id.button_right);
buttonright.setOnClickListener(this);
Button buttonresult = (Button) findViewById(R.id.button_result);
buttonresult.setOnClickListener(this);
}
@Override
public void onClick(View v) {
result_view.setText("");
switch (v.getId()) {
case R.id.button_1:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('1');
textView.setText(sb.toString());
break;
case R.id.button_2:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('2');
textView.setText(sb.toString());
break;
case R.id.button_3:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('3');
textView.setText(sb.toString());
break;
case R.id.button_4:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('4');
textView.setText(sb.toString());
break;
case R.id.button_5:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('5');
textView.setText(sb.toString());
break;
case R.id.button_6:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('6');
textView.setText(sb.toString());
break;
case R.id.button_7:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('7');
textView.setText(sb.toString());
break;
case R.id.button_8:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('8');
textView.setText(sb.toString());
break;
case R.id.button_9:
if (isZero == true) {
sb.deleteCharAt(sb.length() - 1);
isZero = false;
}
sb.append('9');
textView.setText(sb.toString());
break;
case R.id.button_0:
if (isZero == false) {
sb.append('0');
if (sb.length() == 1 ||
!('0' <= sb.charAt(sb.length() - 2) && sb.charAt(sb.length() - 2) <= '9')
&& sb.charAt(sb.length() - 2) != '.') {
isZero = true;
}
}
textView.setText(sb.toString());
break;
case R.id.button_dot:
if (isHasDot == false) {
if (sb.length() == 0 ||
!('0' <= sb.charAt(sb.length() - 1) && sb.charAt(sb.length() - 1) <= '9')) {
sb.append("0.");
} else {
sb.append('.');
}
isHasDot = true;
isZero = false;
}
textView.setText(sb.toString());
break;
case R.id.button_add:
if (sb.length() != 0 &&
(sb.charAt(sb.length() - 1) == '+' || sb.charAt(sb.length() - 1) == '-' || sb.charAt(sb.length() - 1) == '*' || sb.charAt(sb.length() - 1) == '/')) {
sb.setCharAt(sb.length() - 1, '+');
} else if (sb.length() != 0) {
sb.append('+');
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
if (result.matches("[-]?\\d+[.]?\\d*") && sb.length() == 0) {
sb.append(result + "+");
isHasDot = result.matches("[-]?\\d*[.]\\d*");
isZero = "0".equals(result);
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
textView.setText(sb.toString());
break;
case R.id.button_minus:
if (sb.length() != 0 &&
(sb.charAt(sb.length() - 1) == '+' || sb.charAt(sb.length() - 1) == '-' || sb.charAt(sb.length() - 1) == '*' || sb.charAt(sb.length() - 1) == '/')) {
sb.append('(');
zeroStack.push(isZero);
dotStack.push(isHasDot);
leftNum++;
}
if (result.matches("[-]?\\d+[.]?\\d*") && sb.length() == 0) {
sb.append(result + "-");
isHasDot = result.matches("[-]?\\d*[.]\\d*");
isZero = "0".equals(result);
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
sb.append('-');
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
textView.setText(sb.toString());
break;
case R.id.button_mult:
if (sb.length() != 0 &&
(sb.charAt(sb.length() - 1) == '+' || sb.charAt(sb.length() - 1) == '-' || sb.charAt(sb.length() - 1) == '*' || sb.charAt(sb.length() - 1) == '/')) {
sb.setCharAt(sb.length() - 1, '*');
} else if (sb.length() != 0) {
sb.append('*');
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
if (result.matches("[-]?\\d+[.]?\\d*") && sb.length() == 0) {
sb.append(result + "*");
isHasDot = result.matches("[-]?\\d*[.]\\d*");
isZero = "0".equals(result);
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
textView.setText(sb.toString());
break;
case R.id.button_divide:
if (sb.length() != 0 &&
(sb.charAt(sb.length() - 1) == '+' || sb.charAt(sb.length() - 1) == '-' || sb.charAt(sb.length() - 1) == '*' || sb.charAt(sb.length() - 1) == '/')) {
sb.setCharAt(sb.length() - 1, '/');
} else if (sb.length() != 0) {
sb.append('/');
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
if (result.matches("[-]?\\d+[.]?\\d*") && sb.length() == 0) {
sb.append(result + "/");
isHasDot = result.matches("[-]?\\d*[.]\\d*");
isZero = "0".equals(result);
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
}
textView.setText(sb.toString());
break;
case R.id.button_left:
sb.append('(');
leftNum++;
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
textView.setText(sb.toString());
break;
case R.id.button_right:
sb.append(')');
rightNum++;
zeroStack.push(isZero);
dotStack.push(isHasDot);
isZero = false;
isHasDot = false;
textView.setText(sb.toString());
break;
case R.id.button_del:
if (sb.length() != 0) {
if (sb.charAt(sb.length() - 1) == '.') {
isHasDot = false;
if (sb.charAt(sb.length() - 2) == '0') {
sb.deleteCharAt(sb.length() - 1);
}
}
if (sb.charAt(sb.length() - 1) == '(') {
leftNum--;
}
if (sb.charAt(sb.length() - 1) == ')') {
rightNum--;
}
if (sb.charAt(sb.length() - 1) == '0' && isZero == true) {
isZero = false;
}
if (!(sb.charAt(sb.length() - 1) == '.' || '0' <= sb.charAt(sb.length() - 1) && sb.charAt(sb.length() - 1) <= '9')) {
if (!dotStack.isEmpty()) {
isHasDot = dotStack.pop();
}
if (!zeroStack.isEmpty()) {
isZero = zeroStack.pop();
}
}
sb.deleteCharAt(sb.length() - 1);
}
result_view.setText("");
textView.setText(sb.toString());
break;
case R.id.button_ac:
if (sb.length() != 0) {
sb.delete(0, sb.length());
}
isHasDot = false;
isZero = false;
zeroStack.clear();
dotStack.clear();
expression = "";
result = "";
leftNum = 0;
rightNum = 0;
result_view.setText("");
textView.setText("");
break;
case R.id.button_result:
if (sb.length() != 0) {
textView.setText(sb.toString());
isHasDot = false;
isZero = false;
zeroStack.clear();
dotStack.clear();
if (leftNum < rightNum) {
result = "出错";
sb.delete(0, sb.length());
result_view.setText(result);
leftNum = 0;
rightNum = 0;
break;
} else if (leftNum > rightNum) {
while (leftNum > rightNum) {
sb.append(')');
rightNum++;
}
}
if (sb.charAt(0) == '-') {
sb.insert(0, '0');
}
if (sb.charAt(sb.length() - 1) == '+' || sb.charAt(sb.length() - 1) == '-') {
sb.append('0');
}
if (sb.charAt(sb.length() - 1) == '*' || sb.charAt(sb.length() - 1) == '/') {
sb.append('1');
}
for (int i = 1; i < sb.length() - 1; i++) {
char ch = sb.charAt(i);
if (ch == '(' && (sb.charAt(i - 1) == '.' || '0' <= sb.charAt(i - 1) && sb.charAt(i - 1) <= '9')) {
sb.insert(i, '*');
}
if (ch == ')' && '0' <= sb.charAt(i + 1) && sb.charAt(i + 1) <= '9') {
sb.insert(i + 1, '*');
}
}
expression = sb.toString();
sb.delete(0, sb.length());
exchange(expression);
expression = "";
leftNum = 0;
rightNum = 0;
}
result_view.setText(result);
break;
}
}
public void exchange(String expression) {
Queue<Object> queue = new LinkedList<>();
Stack<Character> stack = new Stack<>();
int figureNum = 0;
int operatorNum = 0;
StringBuilder numSb = new StringBuilder();
for (int i = 0; i < expression.length(); i++) {
char ch = expression.charAt(i);
if (ch == '.' || ('0' <= ch && ch <= '9')) {
numSb.append(ch);
} else {
if (numSb.length() != 0) {
queue.offer(new BigDecimal(numSb.toString()));
figureNum++;
numSb.delete(0, numSb.length());
}
if (ch == '-' && expression.charAt(i - 1) == '(' &&
('0' <= expression.charAt(i + 1) && expression.charAt(i + 1) <= '9')) {
numSb.append(ch);
continue;
}
if (ch == '(') {
stack.push(ch);
} else if ((ch == '+' || ch == '-') && !stack.isEmpty() && stack.peek() == '(') {
stack.push(ch);
} else if ((ch == '*' || ch == '/') && !stack.isEmpty() && !(stack.peek() == '*' || stack.peek() == '/')) {
stack.push(ch);
} else {
while (!stack.empty() && stack.peek() != '(') {
queue.offer(stack.pop());
operatorNum++;
}
if (!stack.isEmpty()) {
stack.pop();
}
if (ch != ')') {
stack.push(ch);
}
}
}
}
if (numSb.length() != 0) {
queue.offer(new BigDecimal(numSb.toString()));
figureNum++;
}
while (!stack.empty()) {
queue.offer(stack.pop());
operatorNum++;
}
if (figureNum == operatorNum + 1) {
calculate(queue);
} else {
result = "出错";
}
}
public void calculate(Queue<Object> queue) {
Stack<BigDecimal> stack = new Stack<>();
while (!queue.isEmpty()) {
Object obj = queue.poll();
if (obj.getClass() == Character.class) {
char operator = (Character) obj;
BigDecimal num1 = (BigDecimal) stack.pop();
BigDecimal num2 = (BigDecimal) stack.pop();
BigDecimal subResult;
if (operator == '+') {
subResult = num2.add(num1);
stack.push(subResult);
} else if (operator == '-') {
subResult = num2.subtract(num1);
stack.push(subResult);
} else if (operator == '*') {
subResult = num2.multiply(num1);
stack.push(subResult);
} else {
if ("0".equals(num1.toString())) {
result = "不能除以零";
return;
} else if ("0".equals(num2.toString())) {
stack.push(new BigDecimal("0"));
} else {
subResult = num2.divide(num1, 20, BigDecimal.ROUND_HALF_UP);
stack.push(subResult);
}
}
} else {
stack.push((BigDecimal) obj);
}
}
result = stack.pop().toString();
if (result.matches("[-]?\\d*[.]\\d*")) {
int i = result.length() - 1;
while (result.charAt(i) == '0') {
i--;
}
if (result.charAt(i) == '.') {
i--;
}
result = result.substring(0, i + 1);
}
}
}
- 分析
1、expression,result,textview等会多次使用,因此将其设置为成员变量。
2、显示框根据行数自动放大或缩小。使用textView.setAutoSizeTextTypeUniformWithConfiguration(4, 70, 10, TypedValue.COMPLEX_UNIT_DIP);方法控制。第一个参数表示最小大小,第二个参数表示最大大小,第三个参数表示每次缩小步长,第四个参数表示之前参数的单位(如:dp,sp等)。
- 按钮点击详解
3、除了按下等号键显示计算结果,其余按键都不需要显示,因此将结果显示框设为空。
4、输入数字时,如果前一个是数字“0”,按下其他数字应显示该数字,即显示“1”而不是“01”。
5、按下加减运算符时,如果之前有计算结果,应直接使用该结果运算。
6、表达式优化:以“-”号开头的表达式,可以在前加上零方便计算;如果左括号少于右括号,此表达式无法计算;左括号少于右括号,可以在末尾补全右括号;表达式以“+”“-”号结尾,应补上0,以“*”“/”结尾,应补上1;对于a(b),(a)b应自动补上乘号
- 中缀表达式转后缀表达式
1、遇到数字以及小数点直接保存,遇到符号按照优先级顺序出栈入栈。
2、使用计数器分别记录运算符和数字的个数,如果不匹配,直接显示出错
- 计算
1、在除法运算中,“0/a”应直接显示0、“a/0”应不计算,直接显示不能除以零
2、在最后结果上,“2.000000…”的类似有末尾0的结果应去除末尾0以及小数点
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。
本文标题为:Android简单实现计算器功能
基础教程推荐
- IOS获取系统相册中照片的示例代码 2023-01-03
- iOS中如何判断当前网络环境是2G/3G/4G/5G/WiFi 2023-06-18
- iOS Crash常规跟踪方法及Bugly集成运用详细介绍 2023-01-18
- MVVMLight项目Model View结构及全局视图模型注入器 2023-05-07
- Android Compose自定义TextField实现自定义的输入框 2023-05-13
- iOS开发 全机型适配解决方法 2023-01-14
- Flutter进阶之实现动画效果(三) 2022-10-28
- Android开发Compose集成高德地图实例 2023-06-15
- iOS开发使用XML解析网络数据 2022-11-12
- Android实现短信验证码输入框 2023-04-29