簡單計算機 (使用Swift 4)

魏巍
14 min readDec 5, 2017

--

這篇文章要帶大家用 Swift 做一款簡單的計算機。

我看到 structables 網站的教學,覺得還不錯,所以決定跟著做。不過在跟著做的過程,發現原文有些不足的地方,於是就以原文做基礎,加上自己對於 autolayout 與處理數字的理解,重新做出一款計算機。完成的程式如上圖,就像是大家平常在 iPhone 上會看到的計算機。

1)製作畫面

請打開 Xcode,新增一個專案, Single View App,命名成 Calculator。好了的話,請打開 main.storyboard做畫面。首先要加很多計算機的按鈕到畫面上,請在右下搜尋 Button。拉到畫面上。(我目前設計畫面是用 iPhone 8 ,您可以跟我調成跟我一樣。)

請調整按鈕背景顏色,調成淡灰色(Mercury),按鈕的文字顏色,請選深灰色(Tungsten)。按鈕的大小,請調成寬度 89 point,高度 89 point。按鈕上的文字內容請先改成任何一個您喜歡的數字(我改成 8)。文字大小調成 30。字體調成 Helvetica、粗細 Light。如此,設定好了一顆按鈕。

拷貝剛做好的按鈕,拷貝成橫向4個按鈕,直向 5 顆按鈕,一共 20 顆。之後,把第二顆按鈕刪掉。

把第一顆按鈕拉大,修改上面的文字改成 0。並且把其他數字都加上。如圖,加減乘除按鈕的底色調成橘色(Tangerine),加減乘除按鈕的文字顏色,調成白色(Snow)。

加入一個文字標籤,文字大小我就調成 70。字型設定成 Helvetica,粗細選 Light。設定文字是靠右對齊。

接下來設定一下畫面的 autolayout,想要做出按鈕中間的間距都是 6。

有很多種設定的方法,我打算用 stack view 來幫助我設定畫面。如圖,先把上面四個按鈕包在一個 stack view 裡面。接著把 7、8、9、x 四個按鈕包在一個 stack view 裡面,然後把 4、5、6、- 四個按鈕包在一個 stack view 裡面,之後把 1、2、3、+ 四個按鈕包在一個 stack view 裡面,還要把空格跟等號兩個按鈕包在一個 stack view 裡面。下一個步驟把包著空格跟等號的 stack view,再跟 0一起包在一個 stack view 裡面。最後把這些 stack view 再全部在包在一個 stack view 裡面。

設定這個最大的 stack view 的寬度應該要延長到畫面兩邊。y座標抵住畫面的下方。由於 xcode 9 設定 autolayout 對齊的時候有些邊際是以 safe area 做標準。所以如果發現沒有真的抵住畫面的邊際,而是抵住 safe area 的話,請改成抵住畫面的邊際(superview)。

目前在 iPhone 8 高度是 667 的畫面下。包著所有按鍵的 stack view、其高度應該 469。(也就是 5 個 按鈕的高度,89 * 5 ,加上四個中間的空格,如果每個空格的大小是 6,的話,高度應該是469。但是這個數值應該隨著不同機型的高度而有所調整。所以設定此 stack view 的高度跟整個畫面高度的比例是 469:667。

設定最大的 stack view 裡面的元件排列的方式是 fill equally,中間距離是 6。如此設定之後,就會發現除了最下面一排以外,每一排的stack view 的高度都會拉高到我們想要的高度。

選最上面的 stack view,設定寬度延長到兩邊,設定該 stack view 裡面的元件的排列方式是 fill equally,中間距離是 6。您就會發現最上面的一排 stack view 上的四顆按鈕都會排列成我們想要的樣子。

然後從上面算起來第二個、第三個、第四個 stack view也是相同的設定,設定寬度延長到兩邊,設定該 stack view 裡面的元件的排列方式是 fill equally,中間距離是 6。您就會發現這幾排的 stack view,它們上面的按鈕都會排列成我們想要的樣子。

最後一排 stack view 也是一樣,先把這個包著0個按鈕與一個 stack view 的 stack view,先設定成寬度延長到兩邊,設定該 stack view 裡面的元件的排列方式是 fill equally,中間距離是 6。就會先看到結果如圖顯示。

然後是第五個 stack view 裡面的 stack view,也設定裡面的元件是是 fill equally,中間距離是 6。您就會看到空格跟等號兩個按鈕距離也排好了。

如果您發現最後一排這個 stack view 高度不正確的話,請選這個 stack view。把 alignment 的地方調成 fill (這邊我不確定我是不是不小心按錯了。所以如果您的 stack view 高度正確的話,請不要做這個動作。) 這樣,按鈕的 autolayout 就設定好了。

文字標籤的 autolayout的話,就固定寬度延長到兩邊抵住 margin。固定高度,並且y座標固定距離下面的距離是10。這樣文字標籤的 autolayout也設好了。

最後把文字標籤的顏色改成白色,整個畫面的底色設成黑色。這樣畫面就設定好了。

2)連結畫面上的元件

先連結文字標籤到程式碼中。命名成 label。

接下來連結按鈕:先連數字的按鈕再處理剩下的按鈕。首先連結數字 0 這個按鈕,連結成一個 action,命名成 numbers,type選 UIButton。

接下來把每顆數字按鈕都連結到程式碼中。都連結到同一個方法 numbers 中。

現在按下每顆按鈕都會觸發程式碼 numbers 的方法。為了分辨是哪顆按鈕觸發 numbers 方法,於是設定按鈕的 tag 的屬性:設定每顆按鈕的 tag 數字,比按鈕上的數字大一號。比方說, 按鈕0,我就把tag設成1。按鈕1,就把 tag 設成 2,以此類推。要這樣的設定是因為預設的tag都是0,所以不能從0開始編號,要從 1 開始標號。

3)設定狀態列顏色

設定好了之後。請選 ViewController點 swift,先設定狀態列的顏色是白色的。因為稍早把整個 App 的底色調成黑色,於是把預設黑色的狀態列調成白色的才看得到。

4)按下數字按鈕會顯示數字

按下數字按鈕之後就會觸發 numbers 這個方法。其中,可以用 sender 的 tag,拿到按鈕的標籤。不過由於之前設定標籤的數字是比按鈕的數字多1,所以把這個拿到的標籤數字減1,才是真的是按到的數字。把這個數字存進常數 inputNumber 裡面。要把這個數字用文字標籤顯示出來的話,要把這個數字改成字串,然後用 label 文字標籤來顯示。做到這邊執行程式,按下計算機上的數字,文字標籤就會出現相對應的數字。

不過我們想要做的效果是計算機按到數字,比方說 56,會顯示 56,不會顯示單單的 5 ,然後變成單單的8。所以修改一下程式碼:先判斷文字標籤的文字不是 nil,如果不是 nil,如果文字標籤的文字有值的話, 裡面繼續判斷。如果文字是 0 的話,就跟原來一樣,把文字標籤顯示的文字設成輸入的數字。如果不是0的話,代表之前有輸入數字,就把文字標籤的文字加上輸入的文字,把這個結合的文字,設回給文字標籤顯示。 程式碼文字標籤的文字會加上驚嘆號的原因是,文字標籤的文字是可能有值可能沒值的 optional。如果要做運算的話,要先解開optional包裝。為什麼可以直接在後面加上驚嘆號呢?因為之前已經在if 判斷式中確認真的有值了。這個時候如果執行程式,會發現數字可以正確輸入。

5)按下c 清空數字

如果一般計算機的話,按下 c 按鈕,就會清空數字。要做到這樣的功能,要先回到main.storyboard,把 c 這個按鈕連結到程式碼裡,命名按下 c 會執行叫做 clear 的方法。

在 clear 方法設定,如果使用者按下 c 的話,就把文字標籤的文字設成 0。這時候執行程式,按下 c ,就清空數字變成 0。

6)運算功能

好,我們做到現在做出了輸入數字,以及清空的功能。接下來我們來做運算的功能。先加入一些變數:

numberOnScreen 稍後要存目前畫面上的數字,目前是 0,

previousNumber 要存的運算之前畫面上的數字。

performingMath 要記錄目前是不是在運算過程中,一開始是 false。

在這個簡單的計算機有加減乘除四種運算。把這個四種可能寫成一個列舉,最後還有一個 case 是 none,代表沒有做運算。

再加上一個變數 operation。型別是 operationType,一開始什麼運算都還沒執行,所以設定是 none。

接下來我把運算符號連結到程式碼中,加號,連結成 add;減號,連結成 subtract;乘號,連結成 multiply;除號,連結成divide;等號,連結我命名成 give me answer。

重新設定 clear 按鈕的功能。選到 clear 的時候,除了把文字標籤的文字設成0,其他的變數也要設定回歸初始值。

修改 numbers 方法裡面的內容。按到任何一個數字按鈕的話,最後把文字標籤最後輸入的文字轉型成 Double,存進 numberOnScreen 裡面。要是轉型失敗,就把 0 存進 numberOnScreen 裡面。

按到加號的話,把文字顯示成加號,並且把operationType 設成 add。把 performingMath 設成 true,代表進行運算中。最後把目前畫面上的數字存起來,存進 previous number 裡面。

寫好了加號的功能以後,拷貝裡面的程式碼,貼到其他的運算方法,把裡面的程式碼改一下:減的話改成減號,operation 改成 subtract;乘的話改成乘號,operation 改成 multiply;除的話改成除號,operation 改成 divide。

按下等號執行 giveMeAnswer 方法。在該方法中,先判斷目前是不是正在運算中。如果正在運算中,就做一個 switch 的判斷。如果 case 是 add,就把 previousNumber 加上 numberOnScreen。把運算的結果變成字串,讓文字標籤來顯示。其他的運算也都做相對應的設定。如果 case 是 none 的話,就直接設定顯示0,運算結束之後,就把performMath設成false。做到這邊計算機的初步功能就完成了。不過目前有很多 Bug 需要解決,第一個是如果按下 5 加 8 做計算,答案會是顯示 13.0。想要改成如果沒有小數點後面的數值,就把文字設成整數,不要顯示點0。

請寫一個方法,makeOKNumberString,透過這個方法,我輸入一個數字,就會讓文字標籤顯示正確的字串。方法裡面判斷,如果把輸入的參數做 floor 運算之後,如果數值沒有變,還是跟原本數值的大小一樣的話,代表測試的數值是一個整數。這個情況就把數字轉型成整數,把這個整數變成字串,讓文字標籤去顯示;上面判斷式的結果如果數值不一樣的話,代表測試的數值是小數。這種情況的話,就直接把這樣的小數變成字串,讓文字標籤去顯示。

修改 giveMeAnswer 這個方法,把運算的結果存進 numberOnScreen。用 numberOnScreen 當參數呼叫 makeOKNumberString,就會在文字標籤上顯示正確的文字。做到這邊,如果輸入 3 加 5,得到的答案就真的是8,不會是8.0。

目前還有一些錯誤要修改,如上圖,3 加 5 的話,按下加號,希望不要顯示 +5,而是按下加號顯示加號,按下5的時候顯示 5。不要顯示+5。請修改 numbers 方法,在判斷如果是0後面,同時加上或著文字標籤的文字是 加號、減號、乘號與除號,也都只顯示輸入的文字。這樣就可以修改這個錯誤。

這時候執行程式,輸入 3 加 5 ,就真的只有5,不會是+5,得到答案等於8之後,直接加2,變成10。再乘 5,變成 50。不過這時候,如果按 3 的話,會變成 503。其實我這時候是想重啟一個計算的流程。所以要重新修改程式碼。

新加一個變數 startNew 記錄是不是要重啟一個新的計算。一開始是 true。

修改 clear 方法,使用者按下 clear 也代表要重啟一個計算的流程,再次設定是 startNew 是 true。

修改 giveMeAnswer 方法。運算完,也是設定是 startNew 是 true。

然後修改 numbers 方法,判斷 label 的文字有值之後,判斷如果是一個新的計算流程,就設定文字標籤的文字是 inputNumber,把 startNew 設成 false,不然的話,就做之前的事。現在這個 app 就能正常執行了。

不過如果發生把 2除以3 出現無限小數的話,會變成這樣。這也是需要修改的錯誤。

我希望固定這個文字字串最多只能秀出後面9位數,所以修改一下 makeOKNumberStirng 這個方法:先加入一個變數,okText。這個 okText 是最後我們要顯示的文字。把本來要顯示的字串先存到 okText 裡面。在真的顯示之前,先檢查,如果 OKText 的 count,文字的數目大於等於10的話,那就取 okText,前面 prefix 10個文字。把得到的結果做成一個字串,把這個字串存回 okText 裡面。接著讓 label 文字標籤顯示 okText。現在如果是2除以3的循環小數,就會正確顯示了。

其實還有很多地方需要修正,我想到的比方說要捉出除以0,會發生錯誤。這個需要修正。您還可以加入百分比啦,小數點啦,或是乘方等功能。這就請大家繼續做下去了,我就先做到這邊。這是一款簡單的計算機範例,希望對大家學習程式有幫助。

我有一個粉絲團。會在上面分享學習跟 iOS 相關的文章,歡迎加入。另外我有錄一套完整的 iOS / Swift4 教學。目前在特價中,也歡迎參考。

--

--

魏巍

Swift 講師、作家,以及開發者。 獨立開發 iPhone 與 Android 程式與遊戲,已經上架 40 款App,從企畫、美術、寫程式全部都一手包辦。其中最有名的包括年初上架登上App Store排行榜免費遊戲第一名的「黃色小鴨爆炸了」;與一年前免費遊戲榜第二名的「指認嫌疑犯」。 提供手機程式和遊戲開發課程,