简体   繁体   中英

Unable to animate SwiftUI Shape with included animatable data

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: 弧

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 Angle s isn't animatable.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM