skip to Main Content

I’m trying to animate an arc to the left and right form its center (270 deg in Shape terms). This requires animatable data, which I’ve added, but the arc still doesn’t seem to animate.

The view using the Arc is below. I’ve commented my intentions with the properties.

struct AverageGauge: View {
    
    @State var endAngle: Angle = Angle(degrees: 271.0)
    
    var clockwise: Bool {
        get { endAngle.degrees > 270 ? false : true }
    }
    

    
    var body: some View {
        Arc(startAngle: .degrees(270), endAngle: endAngle,
            clockwise: clockwise)
            .stroke(.red, style: StrokeStyle(lineWidth: 10, lineCap: .round, lineJoin: .round))
            .frame(width: 300, height: 300)
           // Tap gesture as stand in for changing data
            .onTapGesture {
                withAnimation(Animation.easeIn(duration: 10.0)) {
                    endAngle = Angle(degrees: Double.random(in: 180...360))
                }
            }
    }
}

struct Arc: Shape {
    var startAngle: Angle
    var endAngle: Angle
    var clockwise: Bool
    
    // Animatable endAngle
    var endAngleAnimatable: Angle {
        get { endAngle }
        set { endAngle = newValue }
    }
    
    // Animatable clockwise bool 
    var clockwiseAnimatable: Bool {
        get { clockwise }
        set { clockwise = newValue }
    }
    
    func path(in rect: CGRect) -> Path {
        var path = Path()
        path.addArc(center: CGPoint(x: rect.midX, y: rect.midY), radius: rect.width / 2, startAngle: startAngle, endAngle: endAngleAnimatable, clockwise: clockwiseAnimatable)

        return path
    }
}

When I set the clockwise in the Arc to a constant, it still doesn’t animate, so I suppose the Bool isn’t what’s causing the problem.

Here’s a gif of the arc being instantly redrawn rather than animated:
arc

2

Answers


  1. Chosen as BEST ANSWER

    I got this working by using Double for endAngle rather than Angle. The Double is then converted to an Angle using .degrees(Double) in the arc. I guess creating Angles isn't animatable.


  2. Per @Yrb’s suggestion above, I conformed Angle to VectorArithmetic and the animation works without having to change endAngle do a Double:

    extension Angle: VectorArithmetic {
        
        public static var zero = Angle(degrees: 0.0)
        
        public static func + (lhs: Angle, rhs: Angle) -> Angle {
            Angle(degrees: lhs.degrees + rhs.degrees)
        }
        
        public static func - (lhs: Angle, rhs: Angle) -> Angle {
            Angle(degrees: lhs.degrees - rhs.degrees)
        }
        
        public static func += (lhs: inout Angle, rhs: Angle) {
            lhs = Angle(degrees: lhs.degrees + rhs.degrees)
        }
        
        public static func -= (lhs: inout Angle, rhs: Angle) {
            lhs = Angle(degrees: lhs.degrees - rhs.degrees)
        }
        
        public mutating func scale(by rhs: Double) {
            self.degrees = self.degrees * rhs
        }
        
        public var magnitudeSquared: Double {
            get { 0.0 }
        }
    }
    

    magnitudeSquared isn’t properly implemented. Just a filler stub.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search