#12 計算機App:負數、百分比、倒退、連續計算

希望我能盡量用我的思考流程將文章完成,一方面再次確認自己已經了解邏輯,一方面幫助想在這篇文章找到方向的各位。那就跟著新手村選手的我一起實作計算機吧! 🏃‍♀🏃‍♀🏃‍♀

1. 製作畫面

計算機當然有很多按鈕囉!剛好很適合練習StackView,如畫面所示,我總共用了 7 個StackView來排版,另外還有設定按鍵區和顯示區的比例約束條件,以確保在各個機型都能盡量完美呈現。

Figure 1

首先最外層的StackView(Figure 2的第 7 個)約束條件如下,

X:
StackView.Leading = 1.0 * SuperView.Leading + 0
和畫面左邊貼齊。

Y:
StackView.Bottom = 1.0 * SuperView.Bottom + 0
和畫面底部貼齊。

Width:
StackView.Trailing = 1.0 * SuperView.Trailing + 0
和畫面右邊貼齊,加上X的條件可得知Width為填滿畫面。

Height:
StackView.Height = (450:812) * SuperView.Height + 0
StackView高度和畫面高度的比例為450:812,因為在StoryBoard時我是用Xs製作畫面,所以用這個比例(450為設計的Xs按鍵區的高度,812為Xs畫面高度)去設置條件,就能在每個機型都呈現相同比例的按鍵區和顯示區。

Figure 2

不管是垂直還是水平的StackView,都把Distribution設置Fill Equally並給予Spacing數值,就能自動得到每個按鈕的Width和Height,在不同的機型會因應本身尺寸得到不同的Width和Height。

最後再加入一個Label顯示計算結果,約束條件如下,

X:
ResultLabel.Leading = 1.0 * SuperView.Leading + 3
和畫面左邊距離 3pts。

Y:
ResultLabel.Bottom = 1.0 * StackView.Bottom − 10
和StackView頂部距離 10pts。

Width:
ResultLabel.Trailing = 1.0 * SuperView.Trailing − 3
和畫面右邊距離 3pts,加上X的條件可得知Width為距離畫面左右各 3pts。

Height:
Height = 80
直接固定ResultLabel的高度為 80pts。

至於顏色、字型、大小等等就看個人喜好囉!

2. 連結畫面上的元件

目前畫面上的元件有 19 個按鈕、1 個標籤,我將所有數字鍵(0~9)連結到同一個@IBAction,並將數字鍵的tag設成相應的數字以便後續程式使用,但由於所有按鈕的預設tag都是 0,所以我將數字鍵以外的按鈕tag都設為 10。其他元件就依照它的任務去連結Outlet或Action。

Figure 3

3. 按下數字鍵顯示數字

Figure 4

點擊數字鍵會觸發numbers行為。透過sender.tag可以得到相應的數字並存入inputNumber,接著為了安全性先判斷resultLabel是否為nil,不為nil再繼續判斷(因為resultLabel的型別為UILabel!)。如果resultLabel等於0,就把inputNumber轉型成字串存入;若resultLabel不等於0,就把resultLabel的數字加上轉型成字串的inputNumber結合後再存入。

4. 運算功能

宣告operatingSign、currentNumber、previousNumber、isCalculating、startNew方便運算使用,而加減乘除利用enum列舉,後續可以搭配switch判斷讓程式的可讀性更佳。

Figure 5

而+、−、×、÷的程式基本上大同小異,主要是紀錄各種運算的狀態,以便=進行判斷和計算結果,另外也有判斷是否需要呼叫nowAnswer,計算目前為止的結果。

Figure 6

=的部分就先判斷是否正在運算中,再透過switch依照前面+、−、×、÷所紀錄的operation進行運算,最後再修改運算狀態。這邊我想特別說一下previousNumber = 0,如果少了這一行計算機按了=之後無法接著運算唷!因為不管再點擊+、−、×、÷哪一個符號,因為previousNumber != 0就會一直呼叫nowAnswer,就沒完沒了…我在這邊卡了很久🤣

Figure 7

前面提到的nowAnswer如下,和=的判斷一樣。

Figure 8

5. 檢查運算結果是否符合顯示條件

因為計算結果有可能會是無限小數,而畫面顯示的長度並不足夠,所以用okAnswerString方法確保標籤不會出現…的情況。還有,currentNumber、previousNumber的型別都是Double,就算計算答案是整數也會顯示小數點,例如123.0,所以利用floor無條件捨去的方法來判斷,如果判斷前後相等就表示計算結果是整數,就轉型成Int再轉成String存入。

Figure 9

6. 按下 C 鍵清除數字,回到初始值

clear就是讓標籤顯示為0,所有變數回到初始值。

Figure 10

7. +/−、%、⬅︎ 鍵功能

這邊比較有趣的是⬅︎鍵,需要先判斷是否只有 1 位數,如果只有 1 位數就讓標籤顯示為 0 不可為nil;如果不只 1 位數就用dropLast方法去除最後一個數字,再轉型成Double存入。而+/−鍵就是乘以 -1,%鍵就是除以100。

Figure 11

大功告成!這個APP我參考許多網路上的寫法,各種如法炮製…所以希望透過寫文章再幫自己加深記憶和複習,而且其實這個計算機還有許多bug,例如先按+再按−程式無法判斷有變換符號😅就…再接再厲!

Demo

如果有什麼建議歡迎留言~有興趣可以取用我的程式碼🙆🏻‍♀️

--

--