I use a custom ProgressIndicator made with Circle()
and trim
modifier as below.
Problem happens when I use completed
to 0.98
which is close to full.
struct ContentView: View {
let remainingTimeStrokeColor: Color = .secondary
let completedTimeStrokeColor: Color = .blue
@State var completed: Double = 0.70
// MARK: Use 0.98 to check the problem
var body: some View {
ZStack {
Circle()
.stroke(remainingTimeStrokeColor, style: StrokeStyle(lineWidth: 15))
.frame(width: 200, height: 200)
Circle()
.trim(from: 0, to: completed)
.stroke(completedTimeStrokeColor, style: StrokeStyle(lineWidth: 15, lineCap: .square))
.rotationEffect(.degrees(-90))
.frame(width: 200, height: 200)
}
}
}
The normal output with completed = 0.75
:
When it sets to completed = 0.98
, then it looks like fully completed. This is my main problem.
It shows fully completed when using 0.98 or more close to completed value.
What I tried
After many trials and error I figured out that if I don't use the .frame(width: 200, height: 200)
or I use larger frame to show the progress view then I can see the 98% completion properly.
But according to my UI guide provided for my product I have to use this small size progress view.
This is because you used .square
for the blue circle's line cap.
A line with a squared-off end. Core Graphics extends the line beyond the endpoint of the path for a distance equal to half the line width.
For a line width of 15, the stroke at both ends of the line extends beyond the line by 7.5 each, so the line's length is extended by 15 in total. This causes the "gap" that you expect between the two ends to disappear.
For a circle with radius 100, we can estimate the length of the "gap" that should be between the two ends of the line, by calculating:
tan(.pi * 2 * 0.02) * 100
This turns out to be about 12, which is less than 15.
Use the default .butt
line cap instead.