How to Animate Path in SwiftUI

前端 未结 1 1987
北荒
北荒 2021-01-01 01:27

Being unfamiliar with SwiftUI and the fact that there is not much documentation on this new framework yet. I was wondering if anyone was familiar with how it would be possib

相关标签:
1条回答
  • 2021-01-01 01:39

    Animation of paths is showcased in the WWDC session 237 (Building Custom Views with SwiftUI). The key is using AnimatableData. You can jump ahead to 31:23, but I recommend you start at least at minute 27:47.

    You will also need to download the sample code, because conveniently, the interesting bits are not shown (nor explained) in the presentation: https://developer.apple.com/documentation/swiftui/drawing_and_animation/building_custom_views_in_swiftui


    More documentation: Since I originally posted the answer, I continued to investigate how to animate Paths and posted an article with an extensive explanation of the Animatable protocol and how to use it with Paths: https://swiftui-lab.com/swiftui-animations-part1/


    Update:

    I have been working with shape path animations. Here's a GIF.

    And here's the code:

    IMPORTANT: The code does not animate on Xcode Live Previews. It needs to run either on the simulator or on a real device.

    import SwiftUI
    
    struct ContentView : View {
        var body: some View {
            RingSpinner().padding(20)
        }
    }
    
    struct RingSpinner : View {
        @State var pct: Double = 0.0
    
        var animation: Animation {
            Animation.basic(duration: 1.5).repeatForever(autoreverses: false)
        }
    
        var body: some View {
    
            GeometryReader { geometry in
                ZStack {
                    Path { path in
    
                        path.addArc(center: CGPoint(x: geometry.size.width/2, y: geometry.size.width/2),
                                    radius: geometry.size.width/2,
                                    startAngle: Angle(degrees: 0),
                                    endAngle: Angle(degrees: 360),
                                    clockwise: true)
                    }
                    .stroke(Color.green, lineWidth: 40)
    
                    InnerRing(pct: self.pct).stroke(Color.yellow, lineWidth: 20)
                }
            }
            .aspectRatio(1, contentMode: .fit)
                .padding(20)
                .onAppear() {
                    withAnimation(self.animation) {
                        self.pct = 1.0
                    }
            }
        }
    
    }
    
    struct InnerRing : Shape {
        var lagAmmount = 0.35
        var pct: Double
    
        func path(in rect: CGRect) -> Path {
    
            let end = pct * 360
            var start: Double
    
            if pct > (1 - lagAmmount) {
                start = 360 * (2 * pct - 1.0)
            } else if pct > lagAmmount {
                start = 360 * (pct - lagAmmount)
            } else {
                start = 0
            }
    
            var p = Path()
    
            p.addArc(center: CGPoint(x: rect.size.width/2, y: rect.size.width/2),
                     radius: rect.size.width/2,
                     startAngle: Angle(degrees: start),
                     endAngle: Angle(degrees: end),
                     clockwise: false)
    
            return p
        }
    
        var animatableData: Double {
            get { return pct }
            set { pct = newValue }
        }
    }
    
    0 讨论(0)
提交回复
热议问题