Last Run on XCODE 14.2 / iOS 16.2 / Swift 5.7.2
Progress View Ring Link to heading
I was building a Timer app and needed a visual indicator to display the the amount of time left while the countdown was running. A circular progress bar similar to the fitness/activity rings of Apple Watch made the most sense. Sadly, Apple currently doesn’t provide a good API to use such a view in your own apps. However, building such a View in SwiftUI is pretty simple.
1. Draw a circle Link to heading
To build something simlar in SwiftUI, first we need is a builtin View called Circle(), that can be further customized using .stroke.
Circle()
.stroke(.green,style: StrokeStyle(lineWidth: 8))
2. Trim the circle Link to heading
Next we want is for the Circle to be drawn as the the progress moves forward with a full circle signifying the completion of the task being visualized. To achieve this effect, we can use a modifier called .trim that takes two CGFloat(s) a startFraction and an endFraction for the amount of the curve to draw. A thing to keep in mind is the initial start point for the circle drawn. It starts at middle of the right side in the View, and since I wanted the progress circle to be drawn from the top I use a .rotationEffect modifier with an angle of -90 degrees to adjust for it.
Circle()
.trim(from: 0, to: 0.3)
.stroke(.green,style: StrokeStyle(lineWidth: 8))
.rotationEffect(Angle(degrees: -90))
3. Shadow Circle Link to heading
The visual effect I was aiming for required a progress circle on top of a lighter circle. This meant having two overlapping circles enclosed. This can be achieved with the code snippet below using a ZStack and providing a smaller opacity value to the bottom circle.
ZStack {
Circle()
.stroke(.green, style: StrokeStyle(lineWidth: 4))
.opacity(0.3)
Circle()
.trim(from: 0, to: progress)
.stroke(.green,style: StrokeStyle(lineWidth: 8))
.rotationEffect(Angle(degrees: -90))
}
Code Listing Link to heading
This is the complete code listing to create a Progress View Ring in your SwiftUI project.
import SwiftUI
struct RingProgressView: View {
var progress: Double
var body: some View {
VStack {
Text("Progress View")
.font(.largeTitle)
ZStack {
Circle()
.stroke(.green, style: StrokeStyle(lineWidth: 4))
.opacity(0.3)
Circle()
.trim(from: 0, to: progress)
.stroke(.green,style: StrokeStyle(lineWidth: 8))
.rotationEffect(Angle(degrees: -90))
}
.padding()
}
}
}
struct RingProgressView_Previews: PreviewProvider {
static var previews: some View {
RingProgressView(progress: 0.3)
}
}