I am creating my own "circular" progress bar widget in SwiftUI and I am wondering how to approach implementing he following. If the circle progress is at 100% (meaning the circle if full) I want the "start" of the line to have a "faded out" effect, so that the start and end of the line do not "merge". I saw this in the "battery" widgets on iOS. Here is a an example of "full" and "not full" battery widget:
Here is my current widget code:
struct CircleProgressView: View {
@Binding var progress: Float
var body: some View {
ZStack {
Circle()
.stroke(lineWidth: 10)
.opacity(0.3)
.foregroundColor(Color(UIColor.systemGray3))
Circle()
.trim(from: 0.0, to: CGFloat(min(self.progress, 1.0)))
.stroke(style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
.foregroundColor(Color(UIColor.systemGreen))
.rotationEffect(Angle(degrees: 270.0))
}
.padding()
}
}
Any ideas will be helpful.
CodePudding user response:
Here is an approach. I stacked 4 circles:
- the grey base
- one first green circle to receive the shadow
- one circle clipped to a dot with shadow clipshape to get rid of shadows on the sides of the circle
- another green circle to cover the shadow on one side
Here is the code:
struct CircleProgressView: View {
@Binding var progress: Float
var body: some View {
ZStack {
// grey background circle
Circle()
.stroke(lineWidth: 30)
.opacity(0.3)
.foregroundColor(Color(UIColor.systemGray3))
// green base circle to receive shadow
Circle()
.trim(from: 0.0, to: CGFloat(min(self.progress, 0.5)))
.stroke(style: StrokeStyle(lineWidth: 30, lineCap: .round, lineJoin: .round))
.foregroundColor(Color(UIColor.systemGreen))
.rotationEffect(Angle(degrees: 270.0))
// point with shadow, clipped
Circle()
.trim(from: CGFloat(min(self.progress, 1.0))-0.001, to: CGFloat(min(self.progress, 1.0))-0.0005)
.stroke(style: StrokeStyle(lineWidth: 30, lineCap: .round, lineJoin: .round))
.foregroundColor(Color(UIColor.blue))
.shadow(color: .black, radius: 10, x: 0, y: 0)
.rotationEffect(Angle(degrees: 270.0))
.clipShape(
Circle().stroke(lineWidth: 30)
)
// green overlay circle to hide shadow on one side
Circle()
.trim(from: progress > 0.5 ? 0.25 : 0, to: CGFloat(min(self.progress, 1.0)))
.stroke(style: StrokeStyle(lineWidth: 30, lineCap: .round, lineJoin: .round))
.foregroundColor(Color(UIColor.systemGreen))
.rotationEffect(Angle(degrees: 270.0))
}
.padding()
}
}