๐TimerView (scheduledTimer)
Combine โฉ Timer โฉ TimerView (scheduledTimer)
// 2022.03.25: (*) use Timer.scheduledTimer()
import SwiftUI
import Combine
/// ๐ TimerView (Timer.scheduledTimer)
/// ```
/// TimerView { ... }
/// TimerView(every: 2) { ... }
/// TimerView(every: 3, update: { timer in ... }) { ... }
/// ```
struct TimerView<Content: View>: View {
// โญ๏ธ # of seconds between firings of timer
let interval: TimeInterval
// โญ๏ธ timer event handler
let update: (Timer) -> Void
// โญ๏ธ generate timer content
@ViewBuilder var content: () -> Content
// init
init(
every interval: TimeInterval = 1,
update: @escaping (Timer) -> Void = {_ in}, // default: do nothing
@ViewBuilder content: @escaping () -> Content
) {
self.interval = interval
self.content = content
self.update = update
}
// โญ๏ธ detect whether app has gone background
@Environment(\.scenePhase) private var scenePhase
@State private var isActive = true
var body: some View {
content()
.onAppear {
// โญ๏ธ scheduled timer
Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in
// โญ๏ธ if app goes background, stop updating immediately.
guard isActive else { return }
update(timer)
}
}
// โญ๏ธ mark the app inactive once it goes background.
.onChange(of: scenePhase) { newPhase in
isActive = (newPhase == .active)
}
}
}
struct ContentView: View {
@State private var progress: CGFloat = 0
@State private var timeLeft = 5
let duration: TimeInterval = 5
var body: some View {
HStack {
// TimerView 1
TimerView(
every: 1,
update: { timer in
if timeLeft > 0 { timeLeft -= 1 }
else { timer.invalidate() }
}
) {
Text("\(timeLeft)")
.font(.system(.title3, design: .rounded))
.frame(width: 80, height:40)
.background(Capsule().fill(.pink))
}
.padding(.trailing, 20)
// TimerView 2
TimerView(
every: duration/100,
update: { timer in
if progress < 1 { progress += 0.01 }
else { timer.invalidate() }
}
) {
ZStack {
Circle()
.stroke(Color(.systemGray5), lineWidth: 14)
Circle()
.trim(from: 0, to: progress)
.stroke(.green, lineWidth: 12)
.rotationEffect(.degrees(-90))
Text("\(Int(progress * 100))%")
.font(.system(.title3, design: .rounded))
}
}
.frame(100)
}
.padding()
}
}
compare: TimerView - use Timer.publish().
compare: Loading Indicators.
do Animations with Timer.
Last updated