iOSアプリ開発のUIのチュートリアルとして、ストップウォッチアプリを一緒に作っていきましょう。
下記の記事で学習するスキルを中心にチュートリアルにしています。
- ストーリーボードを使ったUI構築
- ButtonやLabelなどのUI部品の使い方
- UIとロジックの連携
- swift 5.2.4
- Xcode 11.6
- macOS 10.15.6 Catalina
- iOS 14.0.1
目次
完成形
まずは完成系のアプリを確認し、イメージを掴みましょう。
「スタート」と「ストップ」ボタンがあり、
スタートボタンを押すとラベルに時間が加算されていき
ストップを押すとその時点での時間が表示されるアプリです。
プロジェクト作成
それでは今回のプロジェクトを作成していきましょう。
まずはSingle View App
を選んでください。
アプリ名はお好きなもので良いですが、ここではStopWatch
としました。
UI作成
今回のアプリではストップウォッチをスタート・ストップさせるUIButtonと
経過時間を表示するUILabelが必要です。
UILabelの配置
まずは経過時間を表示するUILabel
を配置していきましょう。
Main.storyboardを開いて画面上部にUILabelを配置します。
初期値は「00:00:00」と表示したいのでUILabelのテキストを変更しましょう。
UIButtonの配置
スタート・ストップさせるUIButtonを配置します。
場所はどこでも問題ないですが、今回はUILabelの下あたりに配置しました。
さらにボタンのテキストをそれぞれ「スタート」「ストップ」に変更しましょう。
シンプルですが、これでUI部分に関しては完成です。
一度この段階でビルドしておきましょう。
このような画面が表示されれば成功です。
ViewControllerへの紐付け
UI実装の最後にUILabelとUIButtonアクションをViewControllerに定義していきます。
まずはUILabelです。
Ctrl+ドラッグをすると青い線が出るのでViewControllerまで引っ張っていきましょう。
そうすると入力・選択ができるポップアップが表示されます。
今回はNameのみ「timerLabel」と変更しましょう。
最終的に以下の画像のようになっていたらConnectを押しましょう。
次はUIButtonです。
こちらも先ほどと同様にCtrl+ドラッグをしながら青い線をViewControllerまで引っ張っていきましょう。
UILabelと違いUIButtonはアクションを定義するのでConnectionを「Action」に変更します。
次にNameですが、スタートボタンは「tappedStart」、ストップボタンは「tappedStop」と変更します。
最終的に以下の画像のようになっていたらConnectを押しましょう。
紐付けが完了すると、ViewControllerはこのようになっていると思います。
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var timerLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func tappedStart(_ sender: Any) {
}
@IBAction func tappedStop(_ sender: Any) {
}
}
これでUIが完成しました。
ストップウォッチ機能
次はストップウォッチの機能を作っていきましょう。
まずは要件の確認ですがスタートボタンを押すとタイマーが起動し、時間が経過するごとに時間が表示するです。
これを満たすためには次のような流れが必要ですね。
- 「スタート」ボタンを押した時にタイマーが起動する
- 時間が経過するごとにその時の時間が表示される
- ストップボタンを押すと時間が止まる
- 再びスタートボタンを押した時に0秒からタイマーを計測する
それでは実装していきましょう。
タイマーを起動させる
タイマーアプリなので時間の経過を測定する必要があります。
時間を記録しておく変数を用意しておき、一定時間ごとにその変数に値を足していく方針でいきましょう。
まずは経過時間の変数を用意しておきます。
var elapsedTime: Float = 0.0
次に 一定時間ごと
を実現するために今回は Timer
クラスを使いましょう。
Timer
には scheduledTimer()
というクラスメソッドがあるのでこれを使います。
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
// 0.01秒ごとに呼ばれるのでここでelapsedTimeに0.01を足す
self.elapsedTime += 0.01
}
これでタイマーの起動ができました。
経過時間を表示
タイマー部分ができましたので、次は経過時間を表示していきましょう。
しかしまだ elapsedTime
は秒であるので、まずはミリ秒・秒・分に分けていきます。
// ミリ秒は小数点第一位、第二位なので100をかけて100で割った余り
let milliSecond = Int(self.elapsedTime * 100) % 100
// 秒は1・2桁なので60で割った余り
let second = Int(self.elapsedTime) % 60
// 分は経過秒を60で割った余り
let minutes = Int(self.elapsedTime / 60)
これで分けることができました。
ミリ秒は1000ミリ秒で1秒となるため本来は3桁表示が正しいですが、インターバルを0.01秒(10ミリ秒)としているので2桁表示にします。
次は表示です。
self.timerLabel.text = String(format: "%02d:%02d:%02d", minutes, second, milliSecond)
ここでビルドをしてみましょう。
ここまでのソースを載せておきます。
@IBAction func tappedStart(_ sender: Any) {
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
self.elapsedTime += 0.01
// ミリ秒は小数点第一位、第二位なので100をかけて100で割った余り
let milliSecond = Int(self.elapsedTime * 100) % 100
// 秒は1・2桁なので60で割った余り
let second = Int(self.elapsedTime) % 60
// 分は経過秒を60で割った余り
let minutes = Int(self.elapsedTime / 60)
self.timerLabel.text = String(format: "%02d:%02d:%02d", minutes, second, milliSecond)
}
}
ストップ機能
次はストップ機能をつけていきましょう。
実は scheduledTimer()
はTimerを返り値としています。そのTimerをViewController内で変数として持っておきましょう。
var timer: Timer?
@IBAction func tappedStart(_ sender: Any) {
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
self.elapsedTime += 0.01
// ミリ秒は小数点第一位、第二位なので100をかけて100で割った余り
let milliSecond = Int(self.elapsedTime * 100) % 100
// 秒は1・2桁なので60で割った余り
let second = Int(self.elapsedTime) % 60
// 分は経過秒を60で割った余り
let minutes = Int(self.elapsedTime / 60)
self.timerLabel.text = String(format: "%02d:%02d:%02d", minutes, second, milliSecond)
}
}
次は tappedStop
関数の中でタイマーを止めて、 elapsedTime
を初期化します。
@IBAction func tappedStop(_ sender: Any) {
if let t = timer {
// タイマーを止める
t.invalidate()
}
// 経過時間を0秒に初期化
elapsedTime = 0.0
}
ここまで実装できたらこんな感じで動きます。
これでタイマーアプリの完成です!
下に今回のソースコードを全て載せておきます!
import UIKit
class ViewController: UIViewController {
@IBOutlet weak var timerLabel: UILabel!
var elapsedTime: Float = 0.0
var timer: Timer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
@IBAction func tappedStart(_ sender: Any) {
timer = Timer.scheduledTimer(withTimeInterval: 0.01, repeats: true) { (timer) in
self.elapsedTime += 0.01
// ミリ秒は小数点第一位、第二位なので100をかけて100で割った余り
let milliSecond = Int(self.elapsedTime * 100) % 100
// 秒は1・2桁なので60で割った余り
let second = Int(self.elapsedTime) % 60
// 分は経過秒を60で割った余り
let minutes = Int(self.elapsedTime / 60)
self.timerLabel.text = String(format: "%02d:%02d:%02d", minutes, second, milliSecond)
}
}
@IBAction func tappedStop(_ sender: Any) {
if let t = timer {
t.invalidate()
}
elapsedTime = 0.0
}
}
まとめ
お疲れ様でした!
ストップウォッチアプリのチュートリアルを作成しました。
UIやロジックなど基礎が詰まっていますので、2回くらい作成して使い方や考え方を理解していきましょう。