blog

[SwiftUI 100日] タイマーを使ったカウントダウン

SwiftUIとCombineフレームワークと組み合わせると、ユーザーに少しプレッシャーを与えるタイマーをアプリに追加することができます。最も単純な実装は少しの努力でこれを行いますが、解決する必要があ...

Feb 4, 2020 · 3 min. read
シェア

翻訳元www.hackingwithswift.com/books/ios-s

タイマー付きカウントダウン

Foundation、SwiftUI、Combineフレームワークと組み合わせることで、ユーザーに少しプレッシャーを与えるタイマーをアプリケーションに追加することができます。最も単純な実装は少しの努力でこれを行いますが、解決しなければならないバグがあります。

タイマーは1秒に1回起動し、timeRemaining プロパティはタイマーが起動するたびに 1 減算されます。

ContentViewに以下の2つのプロパティを追加します:

@State private var timeRemaining = 100
let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

メインスレッドにタイマーが作成され、起動されます。

もちろん、日付計算の助けを借りてカウントダウンすることも可能ですが、ここではその必要はまったくありません。

ContentViewの一番外側のZStackにonReceive()モディファイアを追加します。

.onReceive(timer) { time in
 if self.timeRemaining > 0 {
 self.timeRemaining -= 1
 }
}

ヒント: 負の値にならないようにテスト条件を追加します。

タイマーのカウントダウンは100から0までですが、数字を表示する必要があります。

Text("Time: \(timeRemaining)")
 .font(.largeTitle)
 .foregroundColor(.white)
 .padding(.horizontal, 20)
 .padding(.vertical, 5)
 .background(
 Capsule()
 .fill(Color.black)
 .opacity(0.75)
 )

適切な場所に配置すれば、レイアウトコードは次のようになるはずです:

ZStack {
 Image("background")
 .resizable()
 .scaledToFill()
 .edgesIgnoringSafeArea(.all)
 VStack {
 Text("Time: \(timeRemaining)")
 .font(.largeTitle)
 .foregroundColor(.white)
 .padding(.horizontal, 20)
 .padding(.vertical, 5)
 .background(
 Capsule()
 .fill(Color.black)
 .opacity(0.75)
 )
 ZStack {

アプリをもう一度実行してみてください。しかし、ここに小さな問題があります:

  1. 現在時刻の表示
  2. ホーム画面に戻るにはCmd+Hをクリックします。
  3. 10秒待つ
  4. アプリアイコンをタップしてアプリに戻ります
  5. タイマーは時間を表示するのですか?

つまり、タイマーはバックグラウンドで数秒間作動し、アプリが戻るまで一時停止します。

アプリがバックグラウンドまたはフォアグラウンドになった場合、それに応じてタイマーを一時停止または再開します。

まず、アプリケーションが現在アクティブかどうかの状態を保存するために、このプロパティを追加します:

@State private var isActive = true

UIApplication.willResignActiveNotification UIApplication.willEnterForegroundNotification 次に、アプリケーションのisActiveを維持するために、さらに2つのonReceive()モディファイアを追加する必要があります。 このために、以下のようにandの通知をキャプチャすることができます:

.onReceive(NotificationCenter.default.publisher(for: UIApplication.willResignActiveNotification)) { _ in
 self.isActive = false
}
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
 self.isActive = true
}

最後に、onReceive(timer)関数を修正して、isActiveの時にカウントダウンしないようにします:

.onReceive(timer) { time in
 guard self.isActive else { return }
 if self.timeRemaining > 0 {
 self.timeRemaining -= 1
 }
}

この小さな修正により、アプリがバックグラウンドに移行すると、カウントダウンは自動的に一時停止します。

Read next