【Swift】iPhone搭載の電卓アプリをStoryBoard無しで作成!
SwiftのXcodeでiPhoneにも入っている電卓(計算機)アプリを全く同じというわけではありませんが、UI画面をドラック&ドロップで簡単に作成できるStoryBoardを使用せず、以下のように作成してみました。
完成品
もし、Swiftで計算機を作成している方や何を作るかで悩んでいる方はこの記事を見て参考にしてみてください。
そして、この作成したアプリは、iPhoneiPadなどにビルドして実際に使用することの確認もできます。
今回はSwiftでiPhoneに搭載されている電卓アプリをStoryBoardを使わずに作成する方法を以下の手順で作成してみます。
⚫︎ 電卓の完成のイメージ
⚫︎ 電卓に必要な部品を設置する
⚫︎ それぞれのボタンのアクションを設定する
⚫︎ 実際に動かしてみる
目次
iPhone搭載の電卓アプリをStoryBoard無しで作成するには
iPhone搭載の電卓アプリをStoryBoard無しで作成するには「Xcode」を使用して作成する必要があります。
しかし、XcodeはMacのPCでしか使用することができませんので注意してください。
また、Xcodeのインストール方法や使い方についてはこちらをご参考ください。
電卓の完成のイメージ
電卓の完成のイメージは以下のようになります。
完成のイメージ
これとほぼ同じように作成していきます。
電卓に必要な部品を設置する
完成のイメージができましたら、Xcodeで下記のようにボタンやラベルなどの部品を設置していきましょう。
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
import UIKit class ViewController: UIViewController { let label = UILabel(frame: CGRect(x:40-10 , y: 150, width:300, height: 100)) let button1 = UIButton(frame: CGRect(x:30 , y: 570, width:70, height: 70)) let button2 = UIButton(frame: CGRect(x:110 , y: 570, width:70, height: 70)) let button3 = UIButton(frame: CGRect(x:190 , y: 570, width:70, height: 70)) let button4 = UIButton(frame: CGRect(x:30 , y: 480, width:70, height: 70)) let button5 = UIButton(frame: CGRect(x:110 , y: 480, width:70, height: 70)) let button6 = UIButton(frame: CGRect(x:190 , y: 480, width:70, height: 70)) let button7 = UIButton(frame: CGRect(x:30 , y: 390, width:70, height: 70)) let button8 = UIButton(frame: CGRect(x:110 , y: 390, width:70, height: 70)) let button9 = UIButton(frame: CGRect(x:190 , y: 390, width:70, height: 70)) let button0 = UIButton(frame: CGRect(x:30 , y: 660, width:145, height: 70)) let buttonAc = UIButton(frame: CGRect(x:30 , y: 300, width:70, height: 70)) let buttonPlusMinus = UIButton(frame: CGRect(x:110 , y: 300, width:70, height: 70)) let buttonPercent = UIButton(frame: CGRect(x:190 , y: 300, width:70, height: 70)) let buttonDivied = UIButton(frame: CGRect(x:270 , y: 300, width:70, height: 70)) let buttonMultiple = UIButton(frame: CGRect(x:270 , y: 390, width:70, height: 70)) let buttonMinus = UIButton(frame: CGRect(x:270 , y: 480, width:70, height: 70)) let buttonPlus = UIButton(frame: CGRect(x:270 , y: 570, width:70, height: 70)) let buttonDot = UIButton(frame: CGRect(x:190 , y: 660, width:70, height: 70)) let buttonEqual = UIButton(frame: CGRect(x:270 , y: 660, width:70, height: 70)) var turn = true var hugoBox: String? var box1: String? var box2: String? var count = 0 override func viewDidLoad() { super.viewDidLoad() layout() } func layout() { view.backgroundColor = .black label.text = "0" label.font = UIFont.systemFont(ofSize: 60.0) label.backgroundColor = .black label.textColor = .white label.textAlignment = .right self.view.addSubview(label) button1.setTitle("1", for: .normal) button1.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button1.backgroundColor = .darkGray button1.layer.cornerRadius = button1.frame.height / 2 self.view.addSubview(button1) button2.setTitle("2", for: .normal) button2.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button2.backgroundColor = .darkGray button2.layer.cornerRadius = button2.frame.height / 2 self.view.addSubview(button2) button3.setTitle("3", for: .normal) button3.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button3.backgroundColor = .darkGray button3.layer.cornerRadius = button3.frame.height / 2 self.view.addSubview(button3) button4.setTitle("4", for: .normal) button4.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button4.backgroundColor = .darkGray button4.layer.cornerRadius = button4.frame.height / 2 self.view.addSubview(button4) button5.setTitle("5", for: .normal) button5.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button5.backgroundColor = .darkGray button5.layer.cornerRadius = button5.frame.height / 2 self.view.addSubview(button5) button6.setTitle("6", for: .normal) button6.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button6.backgroundColor = .darkGray button6.layer.cornerRadius = button6.frame.height / 2 self.view.addSubview(button6) button7.setTitle("7", for: .normal) button7.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button7.backgroundColor = .darkGray button7.layer.cornerRadius = button7.frame.height / 2 self.view.addSubview(button7) button8.setTitle("8", for: .normal) button8.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button8.backgroundColor = .darkGray button8.layer.cornerRadius = button8.frame.height / 2 self.view.addSubview(button8) button9.setTitle("9", for: .normal) button9.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button9.backgroundColor = .darkGray button9.layer.cornerRadius = button9.frame.height / 2 self.view.addSubview(button9) button0.setTitle("0", for: .normal) button0.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) button0.backgroundColor = .darkGray button0.layer.cornerRadius = button0.frame.height / 2 self.view.addSubview(button0) buttonDivied.setTitle("÷", for: .normal) buttonDivied.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonDivied.backgroundColor = .orange buttonDivied.layer.cornerRadius = buttonDivied.frame.height / 2 self.view.addSubview(buttonDivied) buttonMultiple.setTitle("×", for: .normal) buttonMultiple.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonMultiple.backgroundColor = .orange buttonMultiple.layer.cornerRadius = buttonMultiple.frame.height / 2 self.view.addSubview(buttonMultiple) buttonPlus.setTitle("+", for: .normal) buttonPlus.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonPlus.backgroundColor = .orange buttonPlus.layer.cornerRadius = buttonPlus.frame.height / 2 self.view.addSubview(buttonPlus) buttonMinus.setTitle("-", for: .normal) buttonMinus.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonMinus.backgroundColor = .orange buttonMinus.layer.cornerRadius = buttonMinus.frame.height / 2 self.view.addSubview(buttonMinus) buttonDot.setTitle(".", for: .normal) buttonDot.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonDot.backgroundColor = .darkGray buttonDot.layer.cornerRadius = buttonDot.frame.height / 2 self.view.addSubview(buttonDot) buttonEqual.setTitle("=", for: .normal) buttonEqual.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonEqual.backgroundColor = .orange buttonEqual.layer.cornerRadius = buttonEqual.frame.height / 2 self.view.addSubview(buttonEqual) buttonAc.setTitle("AC", for: .normal) buttonAc.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonAc.backgroundColor = .lightGray buttonAc.setTitleColor(.black, for: .normal) buttonAc.layer.cornerRadius = buttonAc.frame.height / 2 self.view.addSubview(buttonAc) buttonPlusMinus.setTitle("+/-", for: .normal) buttonPlusMinus.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonPlusMinus.backgroundColor = .lightGray buttonPlusMinus.setTitleColor(.black, for: .normal) buttonPlusMinus.layer.cornerRadius = buttonPlusMinus.frame.height / 2 self.view.addSubview(buttonPlusMinus) buttonPercent.setTitle("%", for: .normal) buttonPercent.titleLabel?.font = UIFont.systemFont(ofSize: 30.0) buttonPercent.backgroundColor = .lightGray buttonPercent.setTitleColor(.black, for: .normal) buttonPercent.layer.cornerRadius = buttonPercent.frame.height / 2 self.view.addSubview(buttonPercent) } |
実装結果
ボタンやラベルの部品の設置が完了しました。
しかし、ボタンを押しても何も動きません。
それぞれのボタンのアクションを設定する
部品を設置できましたら、次はそれぞれのボタンのアクションを設定します。
各ボタンのアクションのコードをそれぞれ紹介していきます。
0〜9の数字のボタンのアクションを設定する
0〜9の数字のボタンのアクションは以下のように設定します。
⚫︎ ラベルに数字を出力する
⚫︎ 符号が入力されている場合はラベルを上書きする
それぞれのアクションのコードは下記のように記述します。
部品で作成したコードに追加して記述してください。
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() } @objc func clickNum(_ sender: UIButton) { let sentText = label.text! if label.text == "0" { label.text = sender.currentTitle! } else { label.text = sentText + sender.currentTitle! } } func numAction() { button0.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button1.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button2.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button3.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button4.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button5.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button6.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button7.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button8.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) button9.addTarget(self, action: #selector(numClick(_:)), for: .touchUpInside) } |
実装結果
0〜9の数字のボタンを押すと画面に入力した数字が表示されるようになっています。
符号のボタンのアクションを設定する
符号のボタンのアクションは以下のように設定します。
⚫︎ ボタンの押下後は背景色を白に変える
⚫︎ 別の符号ボタンを押すと上書きする
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() } @objc func clickHugo(_ sender: UIButton) { let arrayHugo = [buttonDivied,buttonMultiple,buttonPlus,buttonMinus] hugoBox = sender.currentTitle! let newArray = arrayHugo.filter { $0.backgroundColor != .orange} for i in newArray { i.backgroundColor = .orange i.setTitleColor(.white, for: .normal) } sender.backgroundColor = .white sender.setTitleColor(.orange, for: .normal) box1 = label.text! label.text = "0" count = 0 } func hugoAction() { buttonDivied.addTarget(self, action: #selector(clickHugo(_:)), for: .touchUpInside) buttonMultiple.addTarget(self, action: #selector(clickHugo(_:)), for: .touchUpInside) buttonPlus.addTarget(self, action: #selector(clickHugo(_:)), for: .touchUpInside) buttonMinus.addTarget(self, action: #selector(clickHugo(_:)), for: .touchUpInside) } |
実装結果
符号のボタンを押すと、色が変わり他のボタンを押すと符号が上書きされて色が変わっています。
+/-のボタンのアクションを設定する
+/-のボタンのアクションは以下のように設定します。
⚫︎ 「-」と「+」を切り替えて出力する
(on状態では先頭に「-」、off状態では先頭の「-」を削除)
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() plusMinusAction() } @objc func clickPlusMinus(_ sender: UIButton) { if (turn) { label.text = "-" + label.text! turn = false } else { let text = label.text! let text_del = text.dropFirst(1) label.text = String(text_del) turn = true } } func plusMinusAction() { buttonPlusMinus.addTarget(self, action: #selector(clickPlusMinus(_:)), for: .touchUpInside) } |
実装結果
+/-のボタンを押すと、先頭に「-」がつきもう一度押すと「-」が削除されています。
小数点のボタンのアクションを設定する
小数点のボタンのアクションは以下のように設定します。
⚫︎ 小数点をラベルに出力する
(小数点は一つのみ)
⚫︎ ラベルの値が「0」の場合にボタンを押下すると「0.」となる
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() plusMinusAction() dotAction() } @objc func clickDot(_ sender: UIButton) { if count < 1 { if label.text == "0" { label.text = "0." } else { label.text = label.text! + sender.currentTitle! } } count = count + 1 } func dotAction() { buttonDot.addTarget(self, action: #selector(clickDot(_:)), for: .touchUpInside) } |
実装結果
小数点のボタンを押すと、先頭に「-」がつきもう一度押すと「-」が削除されています。
%のボタンのアクションを設定する
%のボタンのアクションは以下のように設定します。
⚫︎ 数値をパーセントに直した値をラベルに出力する
(何回でも可能)
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() plusMinusAction() dotAction() percentAction() } @objc func clickPercent(_ sender: UIButton) { if label.text != "0" { let text = label.text! let textDouble = Double(text)! let textPercent = textDouble / 100 label.text = String(textPercent) } } func percentAction() { buttonPercent.addTarget(self, action: #selector(clickPercent(_:)), for: .touchUpInside) } |
実装結果
パーセントのボタンを押すと、百分率の計算が行われています。
=のボタンのアクションを設定する場合
=のボタンのアクションは以下のように設定します。
⚫︎ 計算された結果をラベルに出力する
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() plusMinusAction() dotAction() percentAction() equalAction() } @objc func clickEqual(_ sender: UIButton) { box2 = label.text! let firstNum : NSDecimalNumber = NSDecimalNumber(string: box1) let secondNum : NSDecimalNumber = NSDecimalNumber(string: box2) if hugoBox != "" { switch hugoBox { case "+": let result: NSDecimalNumber = firstNum.adding(secondNum) label.text = ("\(result.stringValue)") case "-": let result: NSDecimalNumber = firstNum.subtracting(secondNum) label.text = ("\(result.stringValue)") case "×": let result: NSDecimalNumber = firstNum.multiplying(by: secondNum) label.text = ("\(result.stringValue)") case "÷": let result: NSDecimalNumber = firstNum.dividing(by:secondNum) label.text = ("\(result.stringValue)") default: break } } } func equalAction() { buttonEqual.addTarget(self, action: #selector(clickEqual(_:)), for: .touchUpInside) } |
実装結果
=のボタンを押すと、計算された結果がラベルに表示されています。
ACのボタンのアクションを設定する
ACのボタンのアクションは以下のように設定します。
⚫︎ 設定されている値やアクションを全てクリア(初期化)する
例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
override func viewDidLoad() { super.viewDidLoad() layout() numAction() hugoAction() plusMinusAction() dotAction() percentAction() equalAction() acAction() } @objc func clickAc(_ sender: UIButton) { label.text = "0" hugoBox = nil count = 0 let arrayHugo = [buttonDivied, buttonMultiple, buttonPlus, buttonMinus] let newArray = arrayHugo.filter { $0.backgroundColor != .orange} for i in newArray { i.backgroundColor = .orange i.setTitleColor(.white, for: .normal) } } func acAction() { buttonAc.addTarget(self, action: #selector(clickAc(_:)), for: .touchUpInside) } |
実装結果
ACのボタンを押すと、全ての値やアクションが削除され、リセットされています。
実際に動かしてみる
コードが書けましたら、実際に動かしてみましょう。
実装結果
それぞれのボタンのアクションが正確で計算もきちんとされているので、これで完成です。
まとめ
今回は、SwiftでiPhone搭載の計算機を作成してみました。
iPhoneの電卓のコードはどのようになっているのかわかりませんが、近いところまで作成できたと思います。
また、ボタンを配列にし、filterを使って条件に引っかかるボタンだけ色に変えるというやり方は短いコードで実現できるのでとても便利だと思いました。
しかし、部品の配置するコードはもう少しきれいにかけるのではないかと思いますので、その辺りは改善していきたいです。
ST
株式会社flyhawkのSTです。フライテックメディア事業部でのメディア運営・ライター業務なども担当。愛機はMac Book AirとThinkPad。好きな言語:swift、JS系(Node.js等)。好きなサーバー:AWS。受託開発やプログラミングスクールの運営をしております。ご気軽にお問い合わせください。