github项目地址:https://github.com/13008451162/AndroidMoblieCalculator
1、Ui开发
笔者的Ui制作的制作的比较麻烦仅供参考,在这里使用了多个LinearLayout对屏幕进行了划分。不建议大家这样做最好使用GridLayout会更加快捷简单
笔者大致划分是这样的:
使用了四个大框,在第四个大框里面有多个小框
最终界面如下:
然后在每一个小框写计算机的按键。
代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/TwoArrows_Shrink"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginTop="15dp"
android:layout_marginLeft="10dp"
android:src="@drawable/two_arrows_shrink"/>
<ImageView
android:id="@+id/FourSquares"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="220dp"
android:layout_marginTop="15dp"
android:src="@drawable/four_squares"/>
<ImageView
android:id="@+id/ThreePoints"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginLeft="15dp"
android:clickable="true"
android:layout_marginTop="15dp"
android:src="@drawable/three_points"/>
</LinearLayout>
<EditText
android:id="@+id/Scanf_EditText"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3"
android:background="@null"
android:gravity="bottom|right"
android:text=""
android:lines="1"
android:inputType="textVisiblePassword"
android:textSize="40dp"
android:paddingRight="16dp"
android:textColor="@android:color/black"
android:textStyle="bold" />
<TextView
android:id="@+id/Printf_text"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center|right"
android:text=""
android:textSize="25dp"
android:layout_margin="8dp"
android:paddingRight="13dp"
android:textColor="@android:color/black"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/keyboard"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:orientation="vertical"
android:layout_margin="10dp">
<!-- C % <- / -->
<LinearLayout
android:id="@+id/One"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<!-- C-->
<FrameLayout
android:id="@+id/leftCFrmae"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageButton
android:id="@+id/leftC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="("
android:textSize="25sp"
android:textColor="@android:color/black"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:padding="8dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"/>
</FrameLayout>
<FrameLayout
android:id="@+id/RightCFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp">
<ImageButton
android:id="@+id/RightC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"/>
<TextView
android:layout_width="19dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingLeft="10dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:text=")"
android:textColor="@android:color/black"
android:textSize="25sp" />
</FrameLayout>
<FrameLayout
android:id="@+id/DeleteOneFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/DeleteOne"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="DEL"
android:textColor="@android:color/black"
android:textSize="25sp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"/>
</FrameLayout>
<FrameLayout
android:id="@+id/DivisionFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/Division"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="➗"
android:textColor="@android:color/black"
android:textSize="25sp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"/>
</FrameLayout>
</LinearLayout>
<!-- 7 8 9 x -->
<LinearLayout
android:id="@+id/Two"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="15dp"
>
<FrameLayout
android:id="@+id/SevenNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/SevenNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="7"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/EightNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/EightNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="8"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/NineNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/NineNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="9"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/MultiplyFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:id="@+id/Multiply"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"
android:scaleType="centerInside"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="✖️"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
</LinearLayout>
<!-- 4 5 6 - -->
<LinearLayout
android:id="@+id/Three"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="15dp"
>
<FrameLayout
android:id="@+id/FourNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/FourNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="4"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/FiveNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/FiveNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="5"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/SixNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/SixNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="6"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/BubFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/Sub"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="➖"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
</LinearLayout>
<!-- 1 2 3 + -->
<LinearLayout
android:id="@+id/Four"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="15dp"
>
<FrameLayout
android:id="@+id/OneNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/OneNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="1"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/TwoNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/TwoNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="2"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/ThreeNumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/ThreeNum"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="3"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/AddFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_grey_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="➕"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
</LinearLayout>
<!-- 00 0 . = -->
<LinearLayout
android:id="@+id/Five"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:paddingTop="15dp"
>
<FrameLayout
android:id="@+id/CFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="C"
android:textSize="25sp"
android:textColor="@android:color/black"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:padding="8dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"/>
</FrameLayout>
<FrameLayout
android:id="@+id/ONumFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/O"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:padding="8dp"
android:text="0"
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/PointFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/Point"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_white_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:paddingBottom="10dp"
android:text="."
android:textColor="@android:color/black"
android:textSize="28dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
<FrameLayout
android:id="@+id/equalFrame"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageButton
android:id="@+id/equal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/button_orange_round"
android:layout_marginStart="20dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginLeft="11dp"
android:paddingBottom="15dp"
android:text="="
android:textColor="@android:color/white"
android:textSize="45dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4" />
</FrameLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
我们简单分解一下代码中的重点
1.1 给文本制作阴影并加粗
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="("
android:textSize="25sp"
android:textColor="@android:color/black"
android:layout_gravity="center"
android:layout_marginLeft="10dp"
android:padding="8dp"
android:shadowColor="#80000000"
android:shadowDx="2"
android:shadowDy="2"
android:shadowRadius="4"
android:textStyle="bold/>
android:shadowColor="#80000000"
:表示为该视图的文本添加阴影效果,阴影颜色为半透明黑色(#80000000)。android:shadowDx="2"
:表示阴影在水平方向上的偏移量为2个像素。android:shadowDy="2"
:表示阴影在垂直方向上的偏移量为2个像素。android:shadowRadius="4"
:表示阴影的模糊半径为4个像素。android:textStyle="bold"
:是对TextView(文本视图)的一个属性设置,用于指定文本的字体样式为粗体(加粗)。
2.2 制作圆形按钮
在drawable目录下新建xml文件如下:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/orange" />
<size android:height="60dp" android:width="60dp"/>
</shape>
android:shape
指定图形,常用参数有:
"rectangle"
: 表示创建一个矩形的形状。"oval"
: 表示创建一个椭圆的形状,也就是圆形。"line"
: 表示创建一条线段的形状。"ring"
: 表示创建一个圆环的形状。"line"
: 表示创建一条线段的形状。
solid:用于填充颜色
**size **:用于指定大小,因为是圆形我们这里长宽都要设置为相同
效果如下:
2.3 制作点击变色的按钮
笔者在这里,没有使用点击变色而是使用了动画,后面介绍动画。这里介绍一下怎么点击变色。
首先还是在drawable目录下新建一个xml文件
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定义按下状态的样式 -->
<item android:state_pressed="true">
<shape android:shape="oval">
<solid android:color="@color/Greywhite" />
<size android:height="60dp" android:width="60dp"/>
</shape>
</item>
<!-- 定义普通状态的样式 -->
<item>
<shape android:shape="oval">
<solid android:color="@color/Greywhite4" />
<size android:height="60dp" android:width="60dp"/>
</shape>
</item>
</selector>
设置一个selector,如何设置两个item选项,设置为android:state_pressed="true"
的选项在点击后就会产生对应的变化。
2、点击事件与界面处理
1、禁用输入法修改EditText文本内容
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(activityMainBinding.getRoot());
//禁用输入法修改EditText文本内容
activityMainBinding.ScanfEditText.setInputType(InputType.TYPE_NULL);
//传入各个按键
//功能键
activityMainBinding.C.setOnClickListener(this);
activityMainBinding.DeleteOne.setOnClickListener(this);
//加减乘除,括号,等于
activityMainBinding.add.setOnClickListener(this);
activityMainBinding.Sub.setOnClickListener(this);
activityMainBinding.Multiply.setOnClickListener(this);
activityMainBinding.Division.setOnClickListener(this);
activityMainBinding.leftC.setOnClickListener(this);
activityMainBinding.RightC.setOnClickListener(this);
activityMainBinding.equal.setOnClickListener(this);
//数字,小数点
activityMainBinding.O.setOnClickListener(this);
activityMainBinding.OneNum.setOnClickListener(this);
activityMainBinding.TwoNum.setOnClickListener(this);
activityMainBinding.ThreeNum.setOnClickListener(this);
activityMainBinding.FourNum.setOnClickListener(this);
activityMainBinding.FiveNum.setOnClickListener(this);
activityMainBinding.SixNum.setOnClickListener(this);
activityMainBinding.SevenNum.setOnClickListener(this);
activityMainBinding.EightNum.setOnClickListener(this);
activityMainBinding.NineNum.setOnClickListener(this);
activityMainBinding.Point.setOnClickListener(this);
activityMainBinding.TwoArrowsShrink.setOnClickListener(this);
//长按触发菜单
registerForContextMenu(activityMainBinding.ThreePoints);
}
activityMainBinding.ScanfEditText.setInputType(InputType.TYPE_NULL);
通过设置 InputType.TYPE_NULL
,EditText
将不再响应输入法的输入,用户无法通过软键盘输入文本内容。这样做的目的通常是为了限制用户只能通过其他途径(比如扫码、点击按钮等)来输入文本内容,而不能直接通过键盘输入。如何我们为每个按钮注册监听事件
2、按键缩放动画和实现震动效果
private void animation(View view) {
// 加载缩放动画资源
final AnimatorSet scaleAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.scale_animation);
//实现震动效果
/**
* Vibrator vibrator=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);
* vibrator.vibrate(new long[]{0,100}, -1);
* 从Android API level 26开始,Vibrator类的vibrate()方法被弃用,推荐使用VibrationEffect来实现震动效果。VibrationEffect类提供了更灵活和可控的震动方式。
*/
// 获取Vibrator实例
Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
// 判断Android版本是否大于等于API 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 创建VibrationEffect对象,指定震动模式和震动时长100ms
VibrationEffect vibrationEffect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
// 开始震动
vibrator.vibrate(vibrationEffect);
} else {
// Android版本低于API 26,使用老版本的vibrate方法
//震动时间为100ms
vibrator.vibrate(100);
}
// 开始执行缩放动画
scaleAnimation.setTarget(view);
scaleAnimation.start();
scaleAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 在缩放动画结束时,创建还原动画并执行还原动画
ObjectAnimator restoreAnimationX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
ObjectAnimator restoreAnimationY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
AnimatorSet restoreAnimation = new AnimatorSet();
restoreAnimation.playTogether(restoreAnimationX, restoreAnimationY);
restoreAnimation.start();
}
});
}
首先加载缩放动画资源。
final AnimatorSet scaleAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.scale_animation);
scale_animation
是animator
下设置的动画属性
具体设置如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="scaleX"
android:valueFrom="1.0"
android:valueTo="0.9"
android:duration="100"
android:repeatCount="0"
android:repeatMode="restart"
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
<objectAnimator
android:propertyName="scaleY"
android:valueFrom="1.0"
android:valueTo="0.9"
android:duration="100"
android:repeatCount="0"
android:repeatMode="restart"
android:interpolator="@android:anim/accelerate_decelerate_interpolator" />
</set>
android:propertyName
: 定义要动画化的属性的名称。在这里,scaleX
和scaleY
分别表示水平和垂直方向的缩放。android:valueFrom
: 定义动画的起始值。这里起始值为 1.0,表示不缩放。android:valueTo
: 定义动画的结束值。这里结束值为 0.9,表示缩放到原始大小的 0.9 倍。android:duration
: 定义动画的持续时间,以毫秒为单位。这里持续时间为 100 毫秒,即缩放动画的过程为 0.1 秒。android:repeatCount
: 定义动画重复的次数。这里设置为 0,表示动画不重复。android:repeatMode
: 定义动画重复的模式。这里设置为restart
,表示每次重复动画都从头开始。android:interpolator
: 定义动画的插值器,用于控制动画的变化速率。这里使用了 Android 系统自带的accelerate_decelerate_interpolator
插值器,表示动画先加速后减速。
这个 XML 文件定义了两个属性动画,分别是在水平方向和垂直方向上的缩放动画效果。在 Android 应用中,你可以通过加载这个 XML 文件来应用这个缩放动画,让指定的视图(如 View
或 ImageView
)在缩放动画的作用下,由原始大小缩放到 0.9 倍的大小。
制作动画时,创建了一个 scaleAnimation
缩放动画,然后给该动画添加了一个监听器 AnimatorListenerAdapter
。在监听器的 onAnimationEnd()
方法中,当缩放动画结束时,会执行还原动画。
大致逻辑:
- 创建缩放动画
scaleAnimation
并设置属性动画的相关参数。 - 给
scaleAnimation
添加一个监听器,在缩放动画结束时执行还原动画。 - 创建两个
ObjectAnimator
分别对view
的scaleX
和scaleY
属性进行动画处理,将view
的缩放比例恢复为原始大小(1.0f)。 - 将还原动画
restoreAnimation
中的两个动画一起播放。
3、实现显示框字体大小变化的动画
当我们计算完结果后,我们让计算的结果变大,计算的算式变小
private void DisplayFrameAnimation(View Little_big, View Big_little) {
// 加载动画资源,从25变到40
AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_40);
// 设置目标视图
Little_Big.setTarget(Little_big);
// 启动动画
Little_Big.start();
// 加载动画资源,从40变到25
AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_25);
// 设置目标视图
Big_Little.setTarget(Big_little);
// 启动动画
Big_Little.start();
}
AnimatorInflater
: 这是一个用于加载属性动画的类。它提供了一个方法 loadAnimator()
,可以通过指定资源ID加载属性动画。
this
: 这里的this
指的是当前的上下文,即所在的Activity
。R.animator.text_size_40_25
: 这是指定的属性动画资源的资源ID。在这里,text_size_40_25
是一个位于res/animator
目录下的 XML 文件,它定义了一组属性动画。
同样这样的操作需要动画文件,我们在这里介绍一下字体大小由25变化到40的
<?xml version="1.0" encoding="utf-8"?>
<!-- text_size_change.xml -->
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:propertyName="textSize"
android:valueType="floatType"
android:valueFrom="25"
android:valueTo="40"
android:duration="500"
/>
</set>
<set>
:这是属性动画的根元素,用于定义属性动画集合。在这里,我们只有一个动画,所以只有一个<objectAnimator>
子元素。<objectAnimator>
:这是一个对象动画元素,用于定义属性动画。它有以下属性:android:propertyName="textSize"
:这是要动画化的属性名称,即视图的文本大小属性textSize
。android:valueType="floatType"
:这是动画值的类型,这里是浮点数类型,用于表示文本大小。android:valueFrom="25"
:这是动画的起始值,即文本大小的初始值为 25。android:valueTo="40"
:这是动画的结束值,即文本大小的目标值为 40。android:duration="500"
:这是动画的持续时间,即从起始值到结束值的过渡时间为 500 毫秒。
3、逻辑与算法
1.1 按钮点击结果的分析与处理
package com.example.computermoblie;
import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.app.Service;
import android.os.Build;
import android.os.Bundle;
import android.os.VibrationEffect;
import android.os.Vibrator;
import android.text.InputType;
import android.util.Log;
import android.view.ContextMenu;
import android.view.MenuItem;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import com.example.computermoblie.databinding.ActivityMainBinding;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
// 计算器储存总数据的上限
public List<String> SumNumber = new ArrayList<>();
//计算器存储的数字上限
private StringBuilder Number = new StringBuilder();
//当前输入框字体大小,初始状态为40dp
private int SIzeOfText = 40;
public ActivityMainBinding activityMainBinding;
private boolean GetEqual = false; //表示没有按下等号
private boolean NegativeSymbol = false; //表示不是负数的符号
public String ret; //运算结果
private static final String Del = "Delete"; //表示删除键
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(activityMainBinding.getRoot());
//禁用输入法修改EditText文本内容
activityMainBinding.ScanfEditText.setInputType(InputType.TYPE_NULL);
//传入各个按键
//功能键
activityMainBinding.C.setOnClickListener(this);
activityMainBinding.DeleteOne.setOnClickListener(this);
//加减乘除,括号,等于
activityMainBinding.add.setOnClickListener(this);
activityMainBinding.Sub.setOnClickListener(this);
activityMainBinding.Multiply.setOnClickListener(this);
activityMainBinding.Division.setOnClickListener(this);
activityMainBinding.leftC.setOnClickListener(this);
activityMainBinding.RightC.setOnClickListener(this);
activityMainBinding.equal.setOnClickListener(this);
//数字,小数点
activityMainBinding.O.setOnClickListener(this);
activityMainBinding.OneNum.setOnClickListener(this);
activityMainBinding.TwoNum.setOnClickListener(this);
activityMainBinding.ThreeNum.setOnClickListener(this);
activityMainBinding.FourNum.setOnClickListener(this);
activityMainBinding.FiveNum.setOnClickListener(this);
activityMainBinding.SixNum.setOnClickListener(this);
activityMainBinding.SevenNum.setOnClickListener(this);
activityMainBinding.EightNum.setOnClickListener(this);
activityMainBinding.NineNum.setOnClickListener(this);
activityMainBinding.Point.setOnClickListener(this);
activityMainBinding.TwoArrowsShrink.setOnClickListener(this);
//长按触发菜单
registerForContextMenu(activityMainBinding.ThreePoints);
}
@Override
public void onClick(View view) {
final int Id = view.getId();
// 调用按键动画
animation(view);
//退出
if(Id == R.id.TwoArrows_Shrink){
finish();
}
//功能按钮
if (Id == R.id.C) {
//清空显示
activityMainBinding.ScanfEditText.setText("");
ret = "";
activityMainBinding.PrintfText.setText(ret);
//清空储存的内容
SumNumber.clear();
Number.setLength(0);
//还原字体大小
SIzeOfText = 40;
} else {
if (Id == R.id.leftC) {
if (!GetEqual) {
if (Number.length() > 0) {
char cat = Number.charAt(Number.length() - 1);
if (cat != '.' && !Character.isDigit(cat)) {
SumNumber.add("(");
} else {
//左括号前面没有符号只有数字默认为乘号
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Number.setLength(0);
SumNumber.add("×");
SumNumber.add("(");
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
SumNumber.add("×");
SumNumber.add("(");
} else {
SumNumber.add("(");
}
}
//开头就使用括号的情况
if (SumNumber.isEmpty()){
SumNumber.add("(");
}
}
}
if (Id == R.id.RightC) {
if (!GetEqual) {
if (Number.length() > 0) {
char cat = Number.charAt(Number.length() - 1);
if (cat != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Number.setLength(0);
SumNumber.add(")");
//使得按下后动态计算结果
DynamicCalculation();
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
Log.d("DEL1", SumNumber.toString());
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
SumNumber.add(")");
//使得按下后动态计算结果
DynamicCalculation();
}
}
}
}
if (Id == R.id.DeleteOne) {
if (!GetEqual) {
if (Number.length() > 0) {
Number.deleteCharAt(Number.length() - 1);
} else if (SumNumber.size() > 0) {
try {
Number.setLength(0);
Number.append(SumNumber.remove(SumNumber.size() - 1));
Number.deleteCharAt(Number.length() - 1);
}catch (NumberFormatException e){
Log.d("Number", "出现空值");
}
}else {
ret = "";
activityMainBinding.PrintfText.setText(ret);
}
//删除所有数据后清除结果
if (SumNumber.isEmpty()){
ListComputing(Del);
}
}else {
ListComputing(Del);
}
//使得按下后动态计算结果
DynamicCalculation();
}
//加减乘除
if (Id == R.id.add) {
if (!GetEqual) {
if (Number.length() > 0) {
if (Number.charAt(Number.length() - 1) != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Number.setLength(0);
SumNumber.add("+");
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("+");
}
}
} else {
ListComputing("+");
}
}
if (Id == R.id.Sub) {
if (!GetEqual) {
if (Number.length() > 0) {
if (Number.charAt(Number.length() - 1) != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("-");
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("-");
} else if (str.equals("×") || str.equals("÷")||str.equals("(")) {
Number.append("-");
}
}else {
Number.append("-");
}
} else {
ListComputing("-");
}
}
if (Id == R.id.Multiply) {
if (!GetEqual) {
if (Number.length() > 0) {
if (Number.charAt(Number.length() - 1) != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("×");
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("×");
}
}
} else {
ListComputing("×");
}
}
if (Id == R.id.Division) {
if (!GetEqual) {
if (Number.length() > 0) {
if (Number.charAt(Number.length() - 1) != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("÷");
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (!str.equals("+") && !str.equals("-") && !str.equals("×") && !str.equals("÷") && !str.equals("(")) {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Log.d("String1", String.valueOf(Number));
Number.setLength(0);
SumNumber.add("÷");
}
}
} else {
ListComputing("÷");
}
}
//数字
if (Id == R.id.OneNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("1");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.TwoNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("2");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.ThreeNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("3");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.FourNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("4");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.FiveNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("5");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.SixNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("6");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.SevenNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("7");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.EightNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("8");
// //使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.NineNum) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("9");
//使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.O) {
ClearDisplay();//清空显示
if (!SumNumber.isEmpty()) {
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
SumNumber.add("×");
}
}
Number.append("0");
//使得按下数字后动态计算结果
DynamicCalculation();
}
if (Id == R.id.Point) {
if (Number.length() > 0) {
int t = 0;
for (int i = 0; i < Number.length(); i++) {
if (Number.charAt(i) == '.') {
t++;
}
}
if (t < 1) {
Number.append(".");
}
}
}
if (Id == R.id.equal) {
if (Number.length() > 0) {
if (Number.charAt(Number.length() - 1) != '.') {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Number.setLength(0);
//表示等号已经按下,用于清除文本框
GetEqual = true;
//计算结果
ReversePolish reversePolish = new ReversePolish(SumNumber);
ret = reversePolish.EvaluatePostfixExpressions();
//加载大小变化的动画
DisplayFrameAnimation(activityMainBinding.PrintfText, activityMainBinding.ScanfEditText);
}
} else if (!SumNumber.isEmpty()) {
//判断是不是存在两个相邻的操作
String str = SumNumber.get(SumNumber.size() - 1);
if (str.equals(")")) {
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
Number.setLength(0);
//表示等号已经按下,用于清除文本框
GetEqual = true;
//计算结果
ReversePolish reversePolish = new ReversePolish(SumNumber);
ret = reversePolish.EvaluatePostfixExpressions();
//加载大小变化的动画
DisplayFrameAnimation(activityMainBinding.PrintfText, activityMainBinding.ScanfEditText);
}
}
}
//显示文本框内容
if (Number != null) {
StringBuilder builder = new StringBuilder();
for (String str : SumNumber) {
builder.append(str);
}
builder.append(Number);
activityMainBinding.ScanfEditText.setText(builder);
activityMainBinding.PrintfText.setText(ret);
MaxDisplayFrameAnimation(activityMainBinding.ScanfEditText);
}
}
}
//按键缩放动画和实现震动效果
private void animation(View view) {
// 加载缩放动画资源
final AnimatorSet scaleAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.scale_animation);
//实现震动效果
/**
* Vibrator vibrator=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);
* vibrator.vibrate(new long[]{0,100}, -1);
* 从Android API level 26开始,Vibrator类的vibrate()方法被弃用,推荐使用VibrationEffect来实现震动效果。VibrationEffect类提供了更灵活和可控的震动方式。
*/
// 获取Vibrator实例
Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);
// 判断Android版本是否大于等于API 26
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// 创建VibrationEffect对象,指定震动模式和震动时长
VibrationEffect vibrationEffect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);
// 开始震动
vibrator.vibrate(vibrationEffect);
} else {
// Android版本低于API 26,使用老版本的vibrate方法
vibrator.vibrate(100);
}
// 开始执行缩放动画
scaleAnimation.setTarget(view);
scaleAnimation.start();
scaleAnimation.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
// 在缩放动画结束时,创建还原动画并执行还原动画
ObjectAnimator restoreAnimationX = ObjectAnimator.ofFloat(view, "scaleX", 1.0f);
ObjectAnimator restoreAnimationY = ObjectAnimator.ofFloat(view, "scaleY", 1.0f);
AnimatorSet restoreAnimation = new AnimatorSet();
restoreAnimation.playTogether(restoreAnimationX, restoreAnimationY);
restoreAnimation.start();
}
});
}
// 显示框的动画效果
private void DisplayFrameAnimation(View Little_big, View Big_little) {
/**
* SIzeOfText == 40 由上方40-25 下方25-40
* SIzeOfText == 30 由上方30-25 下方25-30
* SIzeOfText == 25 由上方不变 下方25-30
*/
if (SIzeOfText == 40) {
// 加载动画资源,从25变到40
AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_40);
// 设置目标视图
Little_Big.setTarget(Little_big);
// 启动动画
Little_Big.start();
// 加载动画资源,从40变到25
AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_25);
// 设置目标视图
Big_Little.setTarget(Big_little);
// 启动动画
Big_Little.start();
} else if (SIzeOfText == 30) {
Log.d("SIzeOfText", String.valueOf(SIzeOfText));
// 加载动画资源,从25变到30
AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_30);
// 设置目标视图
Little_Big.setTarget(Little_big);
// 启动动画
Little_Big.start();
// 加载动画资源,从30变到25
AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_30_25);
// 设置目标视图
Big_Little.setTarget(Big_little);
// 启动动画
Big_Little.start();
} else if (SIzeOfText == 25) {
// 加载动画资源,从25变到30
AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_30);
// 设置目标视图
Little_Big.setTarget(Little_big);
// 启动动画
Little_Big.start();
}
}
//显示框的字符达到指定长度使得一行无法放下
private void MaxDisplayFrameAnimation(View Big_littleView) {
int MaxDigit = 0;
for (String str : SumNumber) {
MaxDigit += str.length();
}
MaxDigit += Number.length();
Log.d("StrSize", "num:" + MaxDigit);
if (MaxDigit == 10) {
SIzeOfText = 30; //字体变化为30
// 加载动画资源,从40变到30
AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_30);
// 设置目标视图
Big_Little.setTarget(Big_littleView);
// 启动动画
Big_Little.start();
}
if (MaxDigit > 10 && MaxDigit < 25) activityMainBinding.ScanfEditText.setTextSize(30);
if (MaxDigit == 15) {
SIzeOfText = 25; //字体变化为25
// 加载动画资源,从30变到25
AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_30_25);
// 设置目标视图
Big_Little.setTarget(Big_littleView);
// 启动动画
Big_Little.start();
activityMainBinding.ScanfEditText.setTextSize(25);
}
if (MaxDigit > 15) activityMainBinding.ScanfEditText.setTextSize(25);
}
//加载菜单
@Override
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
Log.d("Tag", "加载菜单");
getMenuInflater().inflate(R.menu.function, menu);
super.onCreateContextMenu(menu, v, menuInfo);
}
//注册菜单点击事件
@Override
public boolean onContextItemSelected(@NonNull MenuItem item) {
Log.d("Tag", "点击事件");
final int Id = item.getItemId();
if (Id == R.id.Log) {
//历史记录
} else if (Id == R.id.SetUp) {
//设置
}
return super.onContextItemSelected(item);
}
//清空显示
private void ClearDisplay() {
//还原显示框大小
activityMainBinding.ScanfEditText.setTextSize(40);
activityMainBinding.PrintfText.setTextSize(30);
//表示已经按下=后,重新输入数字的情况
if (GetEqual) {
GetEqual = false;
activityMainBinding.ScanfEditText.setText("");
ret = "";
//清空储存的内容
SumNumber.clear();
Number.setLength(0);
//还原字体大小
SIzeOfText = 40;
}
}
//连续计算的情况
private void ListComputing(String str) {
if (str.equals(Del)) {
GetEqual = false;
//还原显示框大小
activityMainBinding.ScanfEditText.setTextSize(40);
activityMainBinding.PrintfText.setTextSize(30);
SIzeOfText = 40;
ret = "";
if (Number.length() > 0) {
Number.deleteCharAt(Number.length() - 1);
} else if (SumNumber.size() > 0) {
try {
Number.setLength(0);
Number.append(SumNumber.remove(SumNumber.size() - 1));
Number.deleteCharAt(Number.length() - 1);
}catch (NumberFormatException e){
Log.d("Number", "出现空值");
}
}
} else if (!ret.equals("Error")){
GetEqual = false;
//还原显示框大小
activityMainBinding.ScanfEditText.setTextSize(40);
activityMainBinding.PrintfText.setTextSize(30);
//清空储存的内容
SumNumber.clear();
Number.setLength(0);
//还原字体大小
SIzeOfText = 40;
SumNumber.add(ret);
SumNumber.add(str);
ret = "";
}
}
//使得按下数字后动态计算结果
private void DynamicCalculation() {
if(!SumNumber.isEmpty() && SumNumber.size() > 0){
//将number的数据放入Sumnumber
if (!Number.equals("") && Number != null) {
//保存数据
try {
SumNumber.add(String.valueOf(Number));
} catch (NumberFormatException e) {
Log.d("Number", "出现空值");
}
}
//计算当前结果
ReversePolish reversePolish = new ReversePolish(SumNumber);
ret = reversePolish.EvaluatePostfixExpressions();
//删去暂时存放的数据
SumNumber.remove(SumNumber.size() - 1);
}
}
}
2.2 中缀表达式转后缀表达式,使用逆波兰计算
package com.example.computermoblie;
import android.content.Intent;
import android.util.Log;
import android.view.View;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.Queue;
import java.util.Stack;
public class ReversePolish {
public List<String> SumNumber;
Stack<BigDecimal> SymbolStack = new Stack<>();
//表示没有计算错误的情况
private boolean Error = false;
public static final int LeftBrack = 0; //左括号优先级
public static final int AandS = 1; //加减法
public static final int MandD = 2; //乘除
public static final int RightBrack = 3; //右括号优先级
//中缀转后缀
public Queue<String> InfixToSuffix() {
Queue<String> queue = new ArrayDeque<>();
Stack<String> swapStack = new Stack<>();
for (int i = 0; i < SumNumber.size(); i++) {
String isStr = SumNumber.get(i);
if (!IsSymbol(isStr)) {
queue.add(isStr); // 将数字直接添加到输出队列中
} else {
if (swapStack.isEmpty() || isStr.equals("(")) {
swapStack.push(isStr);
} else if (isStr.equals(")")) {
if(!swapStack.isEmpty()){
while (!swapStack.peek().equals("(")) {
queue.add(swapStack.pop());
}
swapStack.pop(); // 弹出 "("
}
} else {
while (!swapStack.isEmpty() && JudgmentPriority(swapStack.peek(), isStr)) {
queue.add(swapStack.pop());
}
swapStack.push(isStr);
}
}
}
while (!swapStack.isEmpty()) {
queue.add(swapStack.pop());
}
return queue;
}
public String EvaluatePostfixExpressions() {
Error = false; // 表示运算未发现错误
BigDecimal ret = null; // 表示最后的运算结果
Queue<String> queue = InfixToSuffix(); // 获取后缀表达式
Log.d("WQWQ",queue.toString());
while (!queue.isEmpty()) {
String str = queue.remove();
if (!IsSymbol(str)) {
//保存数据
try {
BigDecimal number = new BigDecimal(str);
SymbolStack.push(number);
} catch (NumberFormatException e) {
Log.d("Number","出现空值");
}
} else {
if (SymbolStack.size() < 2) {
Error = true; // 栈中元素不足2个,运算错误
break;
}
BigDecimal op2 = SymbolStack.pop();
BigDecimal op1 = SymbolStack.pop();
BigDecimal result = null;
switch (str) {
case "+":
result = op1.add(op2);
break;
case "-":
result = op1.subtract(op2);
break;
case "×":
result = op1.multiply(op2);
break;
case "÷":
if (op2.compareTo(BigDecimal.ZERO) == 0) {
Error = true; // 除数为零,运算错误
break;
}
result = op1.divide(op2, 3, RoundingMode.HALF_UP);
break;
default:
Error = true; // 非法的运算符,运算错误
break;
}
if (Error) {
break;
} else {
SymbolStack.push(result);
}
}
}
if (Error) {
return "Error"; // 出现错误后直接返回错误信息
} else {
if (!SymbolStack.isEmpty()) {
ret = SymbolStack.pop();
}
// 使用toEngineeringString()方法将结果输出为工程计数法
return ret.toEngineeringString();
}
}
public ReversePolish(List<String> sumNumber) {
SumNumber = sumNumber;
}
//判断是否为符号
public boolean IsSymbol(String str) {
boolean isSymbole = false;
if (str.equals("+")) {
isSymbole = true;
} else if (str.equals("-")) {
isSymbole = true;
} else if (str.equals("×")) {
isSymbole = true;
} else if (str.equals("÷")) {
isSymbole = true;
} else if (str.equals("(")) {
isSymbole = true;
} else if (str.equals(")")) {
isSymbole = true;
}
return isSymbole;
}
//判断优先级
public boolean JudgmentPriority(String PreantStr, String SunStr) {
//默认PreantStr优先级小于SunStr
boolean value = false;
if (SymbolValue(PreantStr) >= SymbolValue(SunStr)) {
value = true;
}
return value;
}
//判断属于什么符号
public int SymbolValue(String str) {
int Value = LeftBrack;
if (str.equals("+")) {
Value = AandS;
} else if (str.equals("-")) {
Value = AandS;
} else if (str.equals("×")) {
Value = MandD;
} else if (str.equals("÷")) {
Value = MandD;
} else if (str.equals("(")) {
Value = LeftBrack;
} else if (str.equals(")")) {
Value = RightBrack;
}
return Value;
}
public List<String> getSumNumber() {
return SumNumber;
}
}
主要代码如上,此外笔者代码存在一个空指针异常(NullPointerException
)的问题,问题出在SumNumber
如果多次使用删除键反复输入数据在删除这种测试操作会导致空指针异常,使得操作SumNumber
的代码逻辑访问到空指针。这个问题笔者解决了很久都没找到问题所在,如有找到问题所在烦请告知笔者,不胜感激。具体异常信息如下:
根据日志信息,异常的原因是在某个地方尝试调用一个对象的toString()
方法,但该对象为空(null),因此无法执行该方法。
根据提供的堆栈跟踪信息,可以看出空指针异常(NullPointerException
)在以下方法中被抛出:
-
com.example.computermoblie.ReversePolish.InfixToSuffix(ReversePolish.java:45)
-
com.example.computermoblie.ReversePolish.EvaluatePostfixExpressions(ReversePolish.java:69)
com.example.computermoblie.MainActivity.onClick(MainActivity.java:189)
com.example.computermoblie.MainActivity.DynamicCalculation(MainActivity.java:872)