3d效果圖設(shè)計制作優(yōu)化網(wǎng)站排名如何
github項目地址:https://github.com/13008451162/AndroidMoblieCalculator
1、Ui開發(fā)
筆者的Ui制作的制作的比較麻煩僅供參考,在這里使用了多個LinearLayout對屏幕進行了劃分。不建議大家這樣做最好使用GridLayout會更加快捷簡單
筆者大致劃分是這樣的:
使用了四個大框,在第四個大框里面有多個小框
最終界面如下:
然后在每一個小框?qū)懹嬎銠C的按鍵。
代碼如下:
<?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"><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid: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"/><ImageViewandroid:id="@+id/FourSquares"android:layout_width="30dp"android:layout_height="30dp"android:layout_marginLeft="220dp"android:layout_marginTop="15dp"android:src="@drawable/four_squares"/><ImageViewandroid: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><EditTextandroid: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" /><TextViewandroid: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" /><LinearLayoutandroid:id="@+id/keyboard"android:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="5"android:orientation="vertical"android:layout_margin="10dp"><!-- C % <- / --><LinearLayoutandroid:id="@+id/One"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><!-- C--><FrameLayoutandroid:id="@+id/leftCFrmae"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/leftC"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/RightCFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_marginStart="20dp"><ImageButtonandroid:id="@+id/RightC"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/DeleteOneFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/DeleteOne"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/DivisionFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/Division"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"android:layout_marginStart="20dp"/><TextViewandroid: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 --><LinearLayoutandroid:id="@+id/Two"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="15dp"><FrameLayoutandroid:id="@+id/SevenNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/SevenNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/EightNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/EightNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/NineNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/NineNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/MultiplyFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageViewandroid: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"/><TextViewandroid: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 - --><LinearLayoutandroid:id="@+id/Three"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="15dp"><FrameLayoutandroid:id="@+id/FourNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/FourNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/FiveNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/FiveNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/SixNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/SixNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/BubFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/Sub"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"android:layout_marginStart="20dp"/><TextViewandroid: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 + --><LinearLayoutandroid:id="@+id/Four"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="15dp"><FrameLayoutandroid:id="@+id/OneNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/OneNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/TwoNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/TwoNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/ThreeNumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/ThreeNum"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/AddFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/add"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_grey_round"android:layout_marginStart="20dp"/><TextViewandroid: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 . = --><LinearLayoutandroid:id="@+id/Five"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:paddingTop="15dp"><FrameLayoutandroid:id="@+id/CFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/C"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/ONumFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/O"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/PointFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/Point"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_white_round"android:layout_marginStart="20dp"/><TextViewandroid: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><FrameLayoutandroid:id="@+id/equalFrame"android:layout_width="wrap_content"android:layout_height="wrap_content"><ImageButtonandroid:id="@+id/equal"android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/button_orange_round"android:layout_marginStart="20dp"/><TextViewandroid: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 給文本制作陰影并加粗
<TextViewandroid: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(文本視圖)的一個屬性設(shè)置,用于指定文本的字體樣式為粗體(加粗)。
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
指定圖形,常用參數(shù)有:
"rectangle"
: 表示創(chuàng)建一個矩形的形狀。"oval"
: 表示創(chuàng)建一個橢圓的形狀,也就是圓形。"line"
: 表示創(chuàng)建一條線段的形狀。"ring"
: 表示創(chuàng)建一個圓環(huán)的形狀。"line"
: 表示創(chuàng)建一條線段的形狀。
solid:用于填充顏色
**size **:用于指定大小,因為是圓形我們這里長寬都要設(shè)置為相同
效果如下:
2.3 制作點擊變色的按鈕
筆者在這里,沒有使用點擊變色而是使用了動畫,后面介紹動畫。這里介紹一下怎么點擊變色。
首先還是在drawable目錄下新建一個xml文件
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 定義按下狀態(tài)的樣式 -->
<item android:state_pressed="true"><shape android:shape="oval"><solid android:color="@color/Greywhite" /><size android:height="60dp" android:width="60dp"/></shape>
</item>
<!-- 定義普通狀態(tài)的樣式 -->
<item><shape android:shape="oval"><solid android:color="@color/Greywhite4" /><size android:height="60dp" android:width="60dp"/></shape>
</item>
</selector>
設(shè)置一個selector,如何設(shè)置兩個item選項,設(shè)置為android:state_pressed="true"
的選項在點擊后就會產(chǎn)生對應(yīng)的變化。
2、點擊事件與界面處理
1、禁用輸入法修改EditText文本內(nèi)容
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(activityMainBinding.getRoot());//禁用輸入法修改EditText文本內(nèi)容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);//數(shù)字,小數(shù)點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);//長按觸發(fā)菜單registerForContextMenu(activityMainBinding.ThreePoints);}activityMainBinding.ScanfEditText.setInputType(InputType.TYPE_NULL);
通過設(shè)置 InputType.TYPE_NULL
,EditText
將不再響應(yīng)輸入法的輸入,用戶無法通過軟鍵盤輸入文本內(nèi)容。這樣做的目的通常是為了限制用戶只能通過其他途徑(比如掃碼、點擊按鈕等)來輸入文本內(nèi)容,而不能直接通過鍵盤輸入。如何我們?yōu)槊總€按鈕注冊監(jiān)聽事件
2、按鍵縮放動畫和實現(xiàn)震動效果
private void animation(View view) {// 加載縮放動畫資源final AnimatorSet scaleAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.scale_animation);//實現(xiàn)震動效果/*** Vibrator vibrator=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);* vibrator.vibrate(new long[]{0,100}, -1);* 從Android API level 26開始,Vibrator類的vibrate()方法被棄用,推薦使用VibrationEffect來實現(xiàn)震動效果。VibrationEffect類提供了更靈活和可控的震動方式。*/// 獲取Vibrator實例Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);// 判斷Android版本是否大于等于API 26if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {// 創(chuàng)建VibrationEffect對象,指定震動模式和震動時長100msVibrationEffect vibrationEffect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);// 開始震動vibrator.vibrate(vibrationEffect);} else {// Android版本低于API 26,使用老版本的vibrate方法//震動時間為100msvibrator.vibrate(100);}// 開始執(zhí)行縮放動畫scaleAnimation.setTarget(view);scaleAnimation.start();scaleAnimation.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {// 在縮放動畫結(jié)束時,創(chuàng)建還原動畫并執(zhí)行還原動畫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
下設(shè)置的動畫屬性
具體設(shè)置如下:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><objectAnimatorandroid: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" /><objectAnimatorandroid: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
: 定義動畫的結(jié)束值。這里結(jié)束值為 0.9,表示縮放到原始大小的 0.9 倍。android:duration
: 定義動畫的持續(xù)時間,以毫秒為單位。這里持續(xù)時間為 100 毫秒,即縮放動畫的過程為 0.1 秒。android:repeatCount
: 定義動畫重復(fù)的次數(shù)。這里設(shè)置為 0,表示動畫不重復(fù)。android:repeatMode
: 定義動畫重復(fù)的模式。這里設(shè)置為restart
,表示每次重復(fù)動畫都從頭開始。android:interpolator
: 定義動畫的插值器,用于控制動畫的變化速率。這里使用了 Android 系統(tǒng)自帶的accelerate_decelerate_interpolator
插值器,表示動畫先加速后減速。
這個 XML 文件定義了兩個屬性動畫,分別是在水平方向和垂直方向上的縮放動畫效果。在 Android 應(yīng)用中,你可以通過加載這個 XML 文件來應(yīng)用這個縮放動畫,讓指定的視圖(如 View
或 ImageView
)在縮放動畫的作用下,由原始大小縮放到 0.9 倍的大小。
制作動畫時,創(chuàng)建了一個 scaleAnimation
縮放動畫,然后給該動畫添加了一個監(jiān)聽器 AnimatorListenerAdapter
。在監(jiān)聽器的 onAnimationEnd()
方法中,當縮放動畫結(jié)束時,會執(zhí)行還原動畫。
大致邏輯:
- 創(chuàng)建縮放動畫
scaleAnimation
并設(shè)置屬性動畫的相關(guān)參數(shù)。 - 給
scaleAnimation
添加一個監(jiān)聽器,在縮放動畫結(jié)束時執(zhí)行還原動畫。 - 創(chuàng)建兩個
ObjectAnimator
分別對view
的scaleX
和scaleY
屬性進行動畫處理,將view
的縮放比例恢復(fù)為原始大小(1.0f)。 - 將還原動畫
restoreAnimation
中的兩個動畫一起播放。
3、實現(xiàn)顯示框字體大小變化的動畫
當我們計算完結(jié)果后,我們讓計算的結(jié)果變大,計算的算式變小
private void DisplayFrameAnimation(View Little_big, View Big_little) { // 加載動畫資源,從25變到40AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_40);// 設(shè)置目標視圖Little_Big.setTarget(Little_big);// 啟動動畫Little_Big.start();// 加載動畫資源,從40變到25AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_25);// 設(shè)置目標視圖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"><objectAnimatorandroid: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"
:這是動畫值的類型,這里是浮點數(shù)類型,用于表示文本大小。android:valueFrom="25"
:這是動畫的起始值,即文本大小的初始值為 25。android:valueTo="40"
:這是動畫的結(jié)束值,即文本大小的目標值為 40。android:duration="500"
:這是動畫的持續(xù)時間,即從起始值到結(jié)束值的過渡時間為 500 毫秒。
3、邏輯與算法
1.1 按鈕點擊結(jié)果的分析與處理
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 {// 計算器儲存總數(shù)據(jù)的上限public List<String> SumNumber = new ArrayList<>();//計算器存儲的數(shù)字上限private StringBuilder Number = new StringBuilder();//當前輸入框字體大小,初始狀態(tài)為40dpprivate int SIzeOfText = 40;public ActivityMainBinding activityMainBinding;private boolean GetEqual = false; //表示沒有按下等號private boolean NegativeSymbol = false; //表示不是負數(shù)的符號public String ret; //運算結(jié)果private static final String Del = "Delete"; //表示刪除鍵@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());setContentView(activityMainBinding.getRoot());//禁用輸入法修改EditText文本內(nèi)容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);//數(shù)字,小數(shù)點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);//長按觸發(fā)菜單registerForContextMenu(activityMainBinding.ThreePoints);}@Overridepublic void onClick(View view) {final int Id = view.getId();// 調(diào)用按鍵動畫animation(view);//退出if(Id == R.id.TwoArrows_Shrink){finish();}//功能按鈕if (Id == R.id.C) {//清空顯示activityMainBinding.ScanfEditText.setText("");ret = "";activityMainBinding.PrintfText.setText(ret);//清空儲存的內(nèi)容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 {//左括號前面沒有符號只有數(shù)字默認為乘號//將number的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}Number.setLength(0);SumNumber.add(")");//使得按下后動態(tài)計算結(jié)果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(")");//使得按下后動態(tài)計算結(jié)果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", "出現(xiàn)空值");}}else {ret = "";activityMainBinding.PrintfText.setText(ret);}//刪除所有數(shù)據(jù)后清除結(jié)果if (SumNumber.isEmpty()){ListComputing(Del);}}else {ListComputing(Del);}//使得按下后動態(tài)計算結(jié)果DynamicCalculation();}//加減乘除if (Id == R.id.add) {if (!GetEqual) {if (Number.length() > 0) {if (Number.charAt(Number.length() - 1) != '.') {//將number的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}Log.d("String1", String.valueOf(Number));Number.setLength(0);SumNumber.add("÷");}}} else {ListComputing("÷");}}//數(shù)字if (Id == R.id.OneNum) {ClearDisplay();//清空顯示if (!SumNumber.isEmpty()) {String str = SumNumber.get(SumNumber.size() - 1);if (str.equals(")")) {SumNumber.add("×");}}Number.append("1");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");// //使得按下數(shù)字后動態(tài)計算結(jié)果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");//使得按下數(shù)字后動態(tài)計算結(jié)果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");//使得按下數(shù)字后動態(tài)計算結(jié)果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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}Number.setLength(0);//表示等號已經(jīng)按下,用于清除文本框GetEqual = true;//計算結(jié)果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的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}Number.setLength(0);//表示等號已經(jīng)按下,用于清除文本框GetEqual = true;//計算結(jié)果ReversePolish reversePolish = new ReversePolish(SumNumber);ret = reversePolish.EvaluatePostfixExpressions();//加載大小變化的動畫DisplayFrameAnimation(activityMainBinding.PrintfText, activityMainBinding.ScanfEditText);}}}//顯示文本框內(nèi)容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);}}}//按鍵縮放動畫和實現(xiàn)震動效果private void animation(View view) {// 加載縮放動畫資源final AnimatorSet scaleAnimation = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.scale_animation);//實現(xiàn)震動效果/*** Vibrator vibrator=(Vibrator)getSystemService(Service.VIBRATOR_SERVICE);* vibrator.vibrate(new long[]{0,100}, -1);* 從Android API level 26開始,Vibrator類的vibrate()方法被棄用,推薦使用VibrationEffect來實現(xiàn)震動效果。VibrationEffect類提供了更靈活和可控的震動方式。*/// 獲取Vibrator實例Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);// 判斷Android版本是否大于等于API 26if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {// 創(chuàng)建VibrationEffect對象,指定震動模式和震動時長VibrationEffect vibrationEffect = VibrationEffect.createOneShot(100, VibrationEffect.DEFAULT_AMPLITUDE);// 開始震動vibrator.vibrate(vibrationEffect);} else {// Android版本低于API 26,使用老版本的vibrate方法vibrator.vibrate(100);}// 開始執(zhí)行縮放動畫scaleAnimation.setTarget(view);scaleAnimation.start();scaleAnimation.addListener(new AnimatorListenerAdapter() {@Overridepublic void onAnimationEnd(Animator animation) {// 在縮放動畫結(jié)束時,創(chuàng)建還原動畫并執(zhí)行還原動畫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變到40AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_40);// 設(shè)置目標視圖Little_Big.setTarget(Little_big);// 啟動動畫Little_Big.start();// 加載動畫資源,從40變到25AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_25);// 設(shè)置目標視圖Big_Little.setTarget(Big_little);// 啟動動畫Big_Little.start();} else if (SIzeOfText == 30) {Log.d("SIzeOfText", String.valueOf(SIzeOfText));// 加載動畫資源,從25變到30AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_30);// 設(shè)置目標視圖Little_Big.setTarget(Little_big);// 啟動動畫Little_Big.start();// 加載動畫資源,從30變到25AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_30_25);// 設(shè)置目標視圖Big_Little.setTarget(Big_little);// 啟動動畫Big_Little.start();} else if (SIzeOfText == 25) {// 加載動畫資源,從25變到30AnimatorSet Little_Big = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_25_30);// 設(shè)置目標視圖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變到30AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_40_30);// 設(shè)置目標視圖Big_Little.setTarget(Big_littleView);// 啟動動畫Big_Little.start();}if (MaxDigit > 10 && MaxDigit < 25) activityMainBinding.ScanfEditText.setTextSize(30);if (MaxDigit == 15) {SIzeOfText = 25; //字體變化為25// 加載動畫資源,從30變到25AnimatorSet Big_Little = (AnimatorSet) AnimatorInflater.loadAnimator(this, R.animator.text_size_30_25);// 設(shè)置目標視圖Big_Little.setTarget(Big_littleView);// 啟動動畫Big_Little.start();activityMainBinding.ScanfEditText.setTextSize(25);}if (MaxDigit > 15) activityMainBinding.ScanfEditText.setTextSize(25);}//加載菜單@Overridepublic void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {Log.d("Tag", "加載菜單");getMenuInflater().inflate(R.menu.function, menu);super.onCreateContextMenu(menu, v, menuInfo);}//注冊菜單點擊事件@Overridepublic boolean onContextItemSelected(@NonNull MenuItem item) {Log.d("Tag", "點擊事件");final int Id = item.getItemId();if (Id == R.id.Log) {//歷史記錄} else if (Id == R.id.SetUp) {//設(shè)置}return super.onContextItemSelected(item);}//清空顯示private void ClearDisplay() {//還原顯示框大小activityMainBinding.ScanfEditText.setTextSize(40);activityMainBinding.PrintfText.setTextSize(30);//表示已經(jīng)按下=后,重新輸入數(shù)字的情況if (GetEqual) {GetEqual = false;activityMainBinding.ScanfEditText.setText("");ret = "";//清空儲存的內(nèi)容SumNumber.clear();Number.setLength(0);//還原字體大小SIzeOfText = 40;}}//連續(xù)計算的情況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", "出現(xiàn)空值");}}} else if (!ret.equals("Error")){GetEqual = false;//還原顯示框大小activityMainBinding.ScanfEditText.setTextSize(40);activityMainBinding.PrintfText.setTextSize(30);//清空儲存的內(nèi)容SumNumber.clear();Number.setLength(0);//還原字體大小SIzeOfText = 40;SumNumber.add(ret);SumNumber.add(str);ret = "";}}//使得按下數(shù)字后動態(tài)計算結(jié)果private void DynamicCalculation() {if(!SumNumber.isEmpty() && SumNumber.size() > 0){//將number的數(shù)據(jù)放入Sumnumberif (!Number.equals("") && Number != null) {//保存數(shù)據(jù)try {SumNumber.add(String.valueOf(Number));} catch (NumberFormatException e) {Log.d("Number", "出現(xiàn)空值");}}//計算當前結(jié)果ReversePolish reversePolish = new ReversePolish(SumNumber);ret = reversePolish.EvaluatePostfixExpressions();//刪去暫時存放的數(shù)據(jù)SumNumber.remove(SumNumber.size() - 1);}}
}
2.2 中綴表達式轉(zhuǎn)后綴表達式,使用逆波蘭計算
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; //左括號優(yōu)先級public static final int AandS = 1; //加減法public static final int MandD = 2; //乘除public static final int RightBrack = 3; //右括號優(yōu)先級//中綴轉(zhuǎn)后綴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); // 將數(shù)字直接添加到輸出隊列中} 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; // 表示運算未發(fā)現(xiàn)錯誤BigDecimal ret = null; // 表示最后的運算結(jié)果Queue<String> queue = InfixToSuffix(); // 獲取后綴表達式Log.d("WQWQ",queue.toString());while (!queue.isEmpty()) {String str = queue.remove();if (!IsSymbol(str)) {//保存數(shù)據(jù)try {BigDecimal number = new BigDecimal(str);SymbolStack.push(number);} catch (NumberFormatException e) {Log.d("Number","出現(xiàn)空值");}} 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; // 除數(shù)為零,運算錯誤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"; // 出現(xiàn)錯誤后直接返回錯誤信息} else {if (!SymbolStack.isEmpty()) {ret = SymbolStack.pop();}// 使用toEngineeringString()方法將結(jié)果輸出為工程計數(shù)法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;}//判斷優(yōu)先級public boolean JudgmentPriority(String PreantStr, String SunStr) {//默認PreantStr優(yōu)先級小于SunStrboolean 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
如果多次使用刪除鍵反復(fù)輸入數(shù)據(jù)在刪除這種測試操作會導(dǎo)致空指針異常,使得操作SumNumber
的代碼邏輯訪問到空指針。這個問題筆者解決了很久都沒找到問題所在,如有找到問題所在煩請告知筆者,不勝感激。具體異常信息如下:
根據(jù)日志信息,異常的原因是在某個地方嘗試調(diào)用一個對象的toString()
方法,但該對象為空(null),因此無法執(zhí)行該方法。
根據(jù)提供的堆棧跟蹤信息,可以看出空指針異常(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)