Skip to content

Instantly share code, notes, and snippets.

@TAATHub
Created March 1, 2025 14:14
Show Gist options
  • Save TAATHub/8f9e7d987c82ef0eea62d2e420d51144 to your computer and use it in GitHub Desktop.
Save TAATHub/8f9e7d987c82ef0eea62d2e420d51144 to your computer and use it in GitHub Desktop.
import SwiftUI
import Combine
struct CountdownView: View {
let countdownSeconds: Int = 10
let numberOfDivision: Int = 36
let handSize: CGSize = .init(width: 8, height: 24)
let radius: CGFloat = 100
@State var count: Int = 10
@State var degree: Double = 360
@State var timer: AnyCancellable?
var degreeInterval: CGFloat {
360.0 / Double(numberOfDivision)
}
var body: some View {
ZStack {
Text("\(count)")
.fontDesign(.rounded)
.font(.system(size: 60, weight: .bold))
.contentTransition(.numericText(countsDown: true)) // This let countdown text transition downwards
.animation(.default, value: count)
ZStack {
// Place hands in a circle
ForEach(Array(0..<numberOfDivision), id: \.self) { angle in
Capsule()
.frame(width: handSize.width, height: handSize.height)
.offset(x: 0, y: radius)
.rotationEffect(.degrees(Double(angle) * degreeInterval))
}
}
.mask {
Circle()
.trim(from: 0, to: degree / 360) // By changing degree using withAnimation, the trim fraction also changes, creating hands animation
.stroke(lineWidth: handSize.height)
.frame(width: radius * 2, height: radius * 2)
.rotationEffect(.degrees(-90.0 - degreeInterval/2)) // Let hands animation start from upward (adjusted to show entire first hand)
}
}
.foregroundStyle(count > 0 ? .black : .red)
.onTapGesture {
count = countdownSeconds
resetTimer()
animateRing()
timer = Timer.publish(every: 1, on: .main, in: .common)
.autoconnect()
.sink { _ in
guard count > 0 else {
resetTimer()
return
}
count -= 1
if count > 0 {
animateRing()
}
}
}
}
private func resetTimer() {
timer?.cancel()
timer = nil
}
private func animateRing() {
degree = 0
withAnimation(.linear(duration: 1)) {
degree += 360
}
}
}
#Preview {
CountdownView()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment