The points for creating a timer app are posted in multiple articles. In this article, I will describe the procedure to actually update the remaining time display every second with the countdown timer.
You can see the sample code from the URL of the Git repository below. https://github.com/msnsk/Qiita_Timer.git
At the moment, pressing the start button will change the timer status to .running, but the remaining time is not yet counted down on the screen. The screen stays at the time set by Picker.
Therefore, we will implement a countdown display of the remaining time, which is the heart of this timer app.
It's also included in the SwiftUI library, but it uses a method called publish in a class called Timer that is provided in the Foundation library, which is the base of the Swift language.
By writing as follows, the timer that is activated every time (1 second) specified by the argument every of the publish method is stored in the variable timer. By using this on the View side, it will be a trigger when you want to activate some action every second. Here, the timer app will be used as a trigger when updating the remaining time every second.
TimeManager.swift
class TimeManager: ObservableObject {
//(Other properties omitted)
//The publish method of the Timer class that fires every second
var timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()
//(Method omitted)
}
Add the .onReceive modifier to the outermost ZStack that contains the TimerView in the MainView. It is reflected in all Views in ZStack.
This .onReceive modifier receives the timer in the TimeManager class fired every second. Then, in the closure after that, write the code to be executed each time the timer is activated.
In the guard let ~ else syntax, write return in the closure so that nothing is done when the timer status is other than .running. If the timer status is .running, proceed to the if statement below it.
In the if statement, if the remaining time is greater than 0, subtract 1 second from the remaining time, and if the remaining time is 0 or less, change the timer status to .stopped.
MainView.swift
struct MainView: View {
@EnvironmentObject var timeManager: TimeManager
var body: some View {
ZStack {
if timeManager.timerStatus == .stopped {
PickerView()
} else {
TimerView()
}
VStack {
Spacer()
ButtonsView()
.padding(.bottom)
}
}
//Executes the code in the closure triggered by a timer that is activated every specified time (1 second)
.onReceive(timeManager.timer) { _ in
//The timer status is.Do nothing except running
guard self.timeManager.timerStatus == .running else { return }
//If the remaining time is greater than 0
if self.timeManager.duration > 0 {
//From the remaining time-1 do
self.timeManager.duration -= 1
//When the remaining time is 0 or less
} else {
//Timer status.Change to stopped
self.timeManager.timerStatus = .stopped
}
}
}
}
Now it looks like a countdown timer. Next time, we will implement alarms.
Recommended Posts