I've created the code for displaying the pie progress bar. I need to add an animation to this progress bar. I tried linear animation but it didn't help. I'm stuck and don't know how to get it to animate. Can someone help? Here's the code.
import SwiftUI
struct PieProgress: View {
    @State var progress: Float
    var body: some View {
        GeometryReader { geometry in
            VStack(spacing:20) {
                HStack{
                    Text("0%")
                    Slider(value: self.$progress)
                    Text("100%")
                }.padding()
                Circle()
                    .stroke(Color.gray, lineWidth: 1)
                    .frame(width: geometry.size.width, height: geometry.size.width, alignment: .center)
                    .padding()
                    .overlay(
                        PieShape(progress: Double(self.progress))
                            .frame(width: geometry.size.width - 10, height: geometry.size.width - 10 , alignment: .center)
                            .foregroundColor(.blue)
                    )
            }
        }
    }
}
struct PieShape: Shape {
    var progress: Double = 0.0
    private let startAngle: Double = (Double.pi) * 1.5
    private var endAngle: Double {
        get {
            return self.startAngle + Double.pi * 2 * self.progress
        }
    }
    func path(in rect: CGRect) -> Path {
        var path = Path()
        let arcCenter =  CGPoint(x: rect.size.width / 2, y: rect.size.width / 2)
        let radius = rect.size.width / 2
        path.move(to: arcCenter)
        path.addArc(center: arcCenter, radius: radius, startAngle: Angle(radians: startAngle), endAngle: Angle(radians: endAngle), clockwise: false)
        path.closeSubpath()
        return path
    }
}
                With updated deprecated methods and now w/o hard-codes

Circle()
    .stroke(Color.gray, lineWidth: 1)
    .overlay(
        PieShape(progress: Double(self.progress))
            .padding(4)
            .foregroundColor(.blue)
    )
    .frame(maxWidth: .infinity)
    .animation(Animation.linear, value: progress) // << here !!
    .aspectRatio(contentMode: .fit)
Test code is here
Here is possible approach (tested & works with Xcode 11.2 / iOS 13.2):
You need to specify animatableData for your shape as below
struct PieShape: Shape { var progress: Double = 0.0
 var animatableData: Double {
     get {
         self.progress
     }
     set {
         self.progress = newValue
     }
 }
 ...
then add animation to Circle
Circle() .stroke(Color.gray, lineWidth: 1) .frame(width: geometry.size.width, height: geometry.size.width, alignment: .center) .padding() .overlay( PieShape(progress: Double(self.progress)) .frame(width: geometry.size.width - 10, height: geometry.size.width - 10 , alignment: .center) .foregroundColor(.blue) ) .animation(Animation.linear) // << here !!
and that's it. For testing (only!) you can add the following in PieProgress
.onAppear {
    DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
        self.progress = 0.72
    }
}
Note: to use PieProgress as reused component it would be reasonable to make progress as @Binding, just in case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With