Home > Blockchain >  Animating variable of a Shape in SwiftUI
Animating variable of a Shape in SwiftUI

Time:10-09

I have an Arc/Circle Shape which I am updating end angle in View, I defined animatableData for the Shape to animate the Shape! How ever I see no animation happen in View! I want reach to same result that could we get from trim without using that modifier! Which correction should I do, to make the animation happen!

struct ContentView: View {
    
    @State private var endAngle: Angle = Angle()
    
    var body: some View {
        
        Button("add") { endAngle  = Angle(degrees: 30.0) }.padding()
        
        CircleShape(lineWidth: 10, startAngle: Angle(degrees: 0.0), endAngle: endAngle)
            .stroke(Color.green, style: StrokeStyle(lineWidth: 10, lineCap: .round))
            .animation(.default, value: endAngle)
 
    }
    
}

struct CircleShape: Shape {
    
    let lineWidth: CGFloat
    var startAngle: Angle
    var endAngle: Angle
    
    var animatableData: Angle {
        get { endAngle }
        set { self.endAngle = newValue }
    }
    
    func path(in rect: CGRect) -> Path {

        return Path { path in
            
            let radius: CGFloat = (min(rect.maxX, rect.maxY) - lineWidth)/2.0
            
            path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                        radius: radius,
                        startAngle: startAngle,
                        endAngle: endAngle,
                        clockwise: false)
            
        }
        
    }
    
}

CodePudding user response:

The problem seems to be the use of Angle.

One of the simplest solutions is to use the CGFloat type which conforms VectorArithmetic.

So changing Angle to CGFloat, your code would look like:

struct ContentView: View {
    
    @State private var endAngle: CGFloat = 0.0
    
    var body: some View {
        
        VStack {
            
            Button("add") { endAngle  = 30.0 }.padding()
            
            CircleShape(lineWidth: 10, startAngle: 0, endAngle: endAngle)
                .stroke(Color.green, style: StrokeStyle(lineWidth: 10, lineCap: .round))
                .animation(.default, value: endAngle)
        }
        .padding()
    }
}

struct CircleShape: Shape {
    
    let lineWidth: CGFloat
    var startAngle: CGFloat
    var endAngle: CGFloat
    
    var animatableData: CGFloat {
        get { endAngle }
        set { endAngle = newValue }
    }
    
    func path(in rect: CGRect) -> Path {

        return Path { path in
            
            let radius: CGFloat = (min(rect.maxX, rect.maxY) - lineWidth)/2.0
            
            path.addArc(center: CGPoint(x: rect.midX, y: rect.midY),
                        radius: radius,
                        startAngle:  Angle(degrees: startAngle),
                        endAngle: Angle(degrees: endAngle),
                        clockwise: false)
        }
    }
}
  • Related