David Koenig's Blog

Gradient Timer - SwiftUI

02/05/2020

In the Gradient Timer App you can stop the seconds. You can select how many seconds the timer should run.

In the Xcode Project we have to update 2 Files which should look like this:

In the GradientTimerManager.swift File, we create the logic of the timer app. The class is an Observable Object.

import SwiftUI class GradientTimerManager: ObservableObject { @Published var secondsElapsed: CGFloat = 0.0 @Published var mode: stopwatchMode = .stopped var timer = Timer() func start(seconds: Int) { self.mode = .running timer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in withAnimation() { self.secondsElapsed += 0.1 if self.secondsElapsed >= CGFloat(seconds) { self.stop() } } } } func pause() { timer.invalidate() mode = .paused } func stop() { timer.invalidate() secondsElapsed = 0.0 mode = .stopped } } enum stopwatchMode { case running case stopped case paused }

In the ContentView.swift File we implement the UI and the actual Timer. The first variable is the for the Gradient Timer Manager which is an ObservedObject. The second variable sets the seconds how long the timer should run.

Also we implemented the gradients for the text and circle! We check if the the timer is running, stopped or paused.

import SwiftUI struct ContentView: View { @ObservedObject var gradientTimerManager = GradientTimerManager() @State private var finalSeconds = 10 var body: some View { VStack { TextView(label: "Timer", size: .custom("Avenir", size: 100)).padding(.top, 100) ZStack { Circle() .stroke(Color.white, lineWidth: 40) .frame(width: 200, height: 200) Circle() .trim(from: 0.0, to: gradientTimerManager.secondsElapsed / CGFloat(finalSeconds)) .stroke(LinearGradient(gradient: Gradient(colors: [Color(red:229/255, green: 181/255, blue: 223/255), Color(red:254/255, green: 208/255, blue: 209/255),Color(red:248/255, green: 249/255, blue: 202/255),Color(red:192/255, green: 235/255, blue: 196/255), Color(red:171/255, green: 217/255, blue: 246/255),Color(red:166/255, green: 171/255, blue: 229/255)]), startPoint: .trailing, endPoint: .leading), lineWidth:40) .frame(width: 200, height: 200) .rotationEffect(Angle(degrees: -90)) VStack { TextView(label: String(format: "%.1f", gradientTimerManager.secondsElapsed), size: .custom("Avenir", size: 40)) TextView(label: "of \(finalSeconds)s", size: .custom("Avenir", size: 30)) }.padding(.top, 50).padding(.bottom, 50) }.padding(.top, 80) .padding(.bottom, 30) if gradientTimerManager.mode == .stopped { Button(action: {self.gradientTimerManager.start(seconds: self.finalSeconds)}) { TextView(label: "Start", size: .title) } } if gradientTimerManager.mode == .running { Button(action: {self.gradientTimerManager.pause()}) { TextView(label: "Pause", size: .title) } } if gradientTimerManager.mode == .paused { HStack { Button(action: {self.gradientTimerManager.start(seconds: self.finalSeconds)}) { TextView(label: "Start", size: .title) } Button(action: {self.gradientTimerManager.stop()}) { TextView(label: "Stop", size: .title) } }.padding(80) } Stepper(value: $finalSeconds, in: 0...120, label: { TextView(label: "Timer is set to \(self.finalSeconds)s", size: .subheadline) }).padding(.leading, 50) .padding(.trailing, 50) .padding(.bottom, 80) .colorScheme(.dark) }.background(Color.gray) .edgesIgnoringSafeArea(.all) } } struct TextView: View { let label: String let size: Font var body: some View { LinearGradient(gradient: Gradient(colors: [Color(red:248/255, green: 249/255, blue: 202/255),Color(red:192/255, green: 235/255, blue: 196/255), Color(red:171/255, green: 217/255, blue: 246/255),Color(red:166/255, green: 171/255, blue: 229/255)]), startPoint: .trailing, endPoint: .leading).mask(Text(label).fontWeight(.black).frame(alignment: .center).font(size)) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

You can download the project at Github:

https://github.com/DKoenig82/swiftui_one/tree/main/gradient_timer-main
    
David Koenig