Animation is animating entire circle and not the progress Xcode 13

250 Views Asked by At

In xCode 11.4 the circle animation was behaving correctly. It was causing a delay in the progress ring (the circle inside the border) a few seconds after the bottom sheet was presented. Now it is delaying the presentation of the entire circle in Xcode 13.2.

Here is full code example with a video example: https://github.com/SimonSays1993/SwiftUI_Part2/blob/main/README.md

In a short summary, this is what's currently happening.

In another view, there is a card, and when I tap on it I toggle a state which displays a bottom sheet. This state then gets passed to the BottomSheetView and then to RingView through Binding.

We then use this value to display the RingView. The RingView has a delay animation base on the Binding variable show. This works fine in presenting the CircleView, but the problem is when the RingView appears I toggle a state to become true to then try and start the animation of the second Circle (call this progress ring) inside the border view of the circle.

Every time the RingView appears the progress ring is already loaded, and its delayed animation is not working.

struct RingView: View {
    var color1 = Color.red
    var color2 = Color.purple
    var width: CGFloat = 88
    var height: CGFloat = 88
    var percent: CGFloat = 88
    
    @Binding var show: Bool
    @State var progressCircle: Bool = false

    var body: some View {
        let multiplier = width / 44
        let progress = 1 - (percent / 100)
        
        return ZStack {
            //The grey border circle
            Circle()
                .stroke(Color.black.opacity(0.1), style: StrokeStyle(lineWidth: 5 * multiplier))
                .frame(width: width, height: height)
            
            Circle()
                .trim(from: progressCircle ? progress : 1, to: 1)
                .stroke(style: StrokeStyle(lineWidth: 5 * multiplier, lineCap: .round))
                .rotationEffect(Angle(degrees: 90))
                .rotation3DEffect(Angle(degrees: 180), axis: (x: 1, y: 0, z: 0))
                .frame(width: width, height: height)
                .animation(.linear.delay(2.0), value: progressCircle)
            
            Text("\(Int(percent))%")
                .font(.system(size: 14 * multiplier))
                .fontWeight(.bold)
        }
        .animation(.linear.delay(1.5), value: show)
        .onAppear {
            self.progressCircle.toggle()
        }
    }
}
1

There are 1 best solutions below

0
On

Solved my answer, I needed to add a longer delay for the progress ring circle. Thanks for the commentators in my post that told me about the new Animation() init

struct RingView: View {
    var color1 = Color.red
    var color2 = Color.purple
    var width: CGFloat = 88
    var height: CGFloat = 88
    var percent: CGFloat = 88
    
    @Binding var show: Bool
    @State var progressCircle: Bool = false
    
    var body: some View {
        let multiplier = width / 44
        let progress = 1 - (percent / 100)
        
        return ZStack {
            //Inactive String, the grey circle
            Circle()
                .stroke(Color.black.opacity(0.1), style: StrokeStyle(lineWidth: 5 * multiplier))
                .frame(width: width, height: height)
            
            Circle()
                .trim(from: progressCircle ? progress : 1, to: 1)
                .stroke(style: StrokeStyle(lineWidth: 5 * multiplier, lineCap: .round))
                .rotationEffect(Angle(degrees: 90))
                .rotation3DEffect(Angle(degrees: 180), axis: (x: 1, y: 0, z: 0))
                .frame(width: width, height: height)
                .animation(.linear(duration: 1.0).delay(2.0), value: progressCircle)
            
            Text("\(Int(percent))%")
                .font(.system(size: 14 * multiplier))
                .fontWeight(.bold)
        }
        .animation(.linear.delay(0.5), value: show)
        .onAppear {
            self.progressCircle.toggle()
        }
    }
}