wolfmasa's blog

フロンターレとプログラミング関係の話題を、気が向いたときにつぶやくブログです。

Apple Watch アプリを作る WKInterfaceTimer編

はじめに

Apple Watch用のアプリを作ってみようと思います。

まずは手始めに簡単なタイマーアプリを作ってみます。

準備

とりあえずiOSアプリと同じような準備が必要です。

MacXcodeが必要なのは周知の事実です。私が使っているのは2013年モデルということもあり、Xcodeが重い重い・・・特にシミュレータの起動が遅いので困っていますが、それでもなんとか開発はできています。(気長にいきましょう)

開発をしていると、当然実機でうごかしたい、動かす必要があるので、Apple Watch本体や、本体にデプロイするためのDeveloperアカウント(有料)が必要です。

確か、最近のiOS開発では、無料のアカウントでもiPhoneで動かすことができると聞いた気がしますが、私の調べた範囲ではWatchは無理らしいです。らしい、と書いたのは、記事の書かれた時期や、そのiPhone開発者に向けた権限の変更をふまえてもWatchは無料ではできない言及している記事が見つからなかったためです。

Story Board

まずStory Boardをいじってみます。

基本的にいつものiOS開発と同じですが、Viewの制約が思っていた以上に大きい。

特に、ボタンやラベル並べようとすると、サイズを小さくしても縦方向にしか追加できず、横に並べるやり方がわからなくて少し困った。

幸い、調べたらGroupというオブジェクト?を使って、サイズを小さくする事で横にはならんだけど、それでも3つ以上のボタンを並べたりはできないらしい。

Timerの表示

タイマーを作成するのにうってつけのViewがあります。

WKInterfaceTimerというもので、配置すれば"59:59"のようないかにも時間が表示されるようなViewがあらわれます。

あとは、このWKInterfaceTimerをコードから制御すればよいだけです。

(もちろん制御するためのボタンも追加しましょう)

Timerの制御

これから私の書いたサンプルをベースに、制御の仕方を簡単に紹介します。

@IBOutlet var timerView: WKInterfaceTimer!

WKInterfaceController(UIKitで言う所のViewController)でこのように定義しておくことにします。

スタート

timerView.start()

これだけ、あら簡単。これでカウントアップが開始されます。

カウントダウン

カウントダウンするためには、カウントする時間をセットする必要があります。

セットするためにはsetDateを使うのですが、引数はDate型なので、それを作ってあげる必要があります。

var countDownSecond: int = 30
timerView.start()
timerView.setDate(Date(timeIntervalSinceNow: TimeInterval(countDownSecond+1)))

ここで注意なのは、スタートしてからセットしないと秒数が飛んだように見えるということです。

あとは、時間をセットするためにDateが必要で、そのDateを作るためにさらにTimeIntervalが必要になるということくらいでしょうか。あとTimeIntervalの引数も0はじまりなのか、1ずれるので加算しています。

ストップ

timerView.stop()

基本的にはこれで止まります。あら、かんたん。

が、

問題はここからです。

表示上は止まっているのですが、実はこれ表示の更新を止めているだけ。

もう一度スタートを実行をすると、止まったところからではなく、ずっと裏で動いていた時間分だけ先に進んだ表示になります。

これは少し考えればわかりますが、Dateを指定しているということは、目標の日時を設定しているため、現在の日時との差分をただ表示するという動作になっているからです。

なので、stopをじっこうしても、目標の日時は変わらないので、再度startをした際に飛んで動き出すような表示になってしまいます。

一時停止

そのままstart/stopを読んでも一時停止にはならないので、一時停止をしたい場合には自分で実装してあげる必要があります。

正しい方針はわかりませんが、とりあえず私はシンプルな方法を試しました。

  • stopされたときに、残りの時間を記憶しておく
  • startされたときに、残りの時間と今の時間との差分(止まっている間に消費した時間)計算し、差分を目標時間に加算する

という感じです。

func stopTimer(){
  suspendedTime = targetDate.timeIntervalSinceNow
  timeView.stop()
}

func startTimer(){
  timeView.start()
  if(suspendedTime != nil){
    targetDate = targetDate.addingTimeInterval(suspendedTime! - targetDate.timeIntervalSinceNow)
    suspndedTime = nil
  }else{
    targetDate = Date(timeIntervalSinceNow: TimeInterval(targetSec))
  }
  timerView.setDate(targetDate)
}

サンプルなので一部省略していますが、基本的にはこの流れで一時停止っぽいことができました。

まずはめでたしめでたし。