import SwiftUI
struct ProgressRing: View {
let progress: Double
var body: some View {
ZStack {
Circle()
.stroke(.quaternary, lineWidth: 10)
Circle()
.trim(from: 0, to: progress)
.stroke(.teal, style: StrokeStyle(lineWidth: 10, lineCap: .round))
.rotationEffect(.degrees(-90))
}
.frame(width: 72, height: 72)
}
}Implementation notes
trim is ideal for progress and reveal animations because it works on the normalized length of a shape.
strokeBorder keeps the stroke inside insettable shapes, which is often cleaner for cards and controls.
Paths should be built from the current rect or size whenever the shape must scale.
Checklist
Clamp progress between 0 and 1.
Use round line caps for circular progress indicators.
Preview with Dynamic Type if the shape sits near text.
Related reference
SwiftUI Canvas Drawing Context
Use Canvas when a visual is easier to draw than compose from many nested views, such as sparklines, badges, waveforms, and lightweight charts.
SwiftUI Gradients and ShapeStyle
Choose linear, radial, angular, image, and mesh-style fills based on the job the color is doing in the interface.
SwiftUI clipShape, mask, and contentShape
Clipping controls what is visible, masking controls alpha, and contentShape controls where interaction happens.