【问题标题】:How to Animate Path in SwiftUI如何在 SwiftUI 中为路径设置动画
【发布时间】:2019-11-14 17:00:42
【问题描述】:

不熟悉 SwiftUI,而且关于这个新框架的文档还很少。我想知道是否有人熟悉如何在 SwiftUI 中为 Path 设置动画。

例如给定一个视图,让我们说这个简单的RingView

struct RingView : View {   
    var body: some View {
        GeometryReader { geometry in
            Group {
                // create outer ring path
                Path { path in
                    path.addArc(center: center,
                                radius: outerRadius,
                                startAngle: Angle(degrees: 0),
                                endAngle: Angle(degrees: 360),
                                clockwise: true)
                }
                .stroke(Color.blue)

                // create inner ring
                Path { path in
                    path.addArc(center: center,
                                radius: outerRadius,
                                startAngle: Angle(degrees: 0),
                                endAngle: Angle(degrees: 180),
                                clockwise: true)
                }
                .stroke(Color.red)
                .animation(.basic(duration: 2, curve: .linear))
            }
        }
        .aspectRatio(1, contentMode: .fit)
    }
}

显示的是:

现在我想知道如何为内环设置动画,即蓝线内的红线。我要做的动画将是一个简单的动画,其中路径从开始出现并遍历到结束。

使用 CoreGraphics 和旧的 UIKit 框架相当简单,但看起来不像在内部路径中添加一个简单的 .animation(.basic(duration: 2, curve: .linear)) 并使用 withAnimation 块显示视图可以做任何事情。

我查看了 Apple 提供的关于 SwiftUI 的教程,但它们实际上只涵盖了更深入的视图上的移动/缩放动画,例如 Image

关于如何在 SwiftUI 中为 PathShape 设置动画的任何指导?

【问题讨论】:

    标签: swift animation swiftui


    【解决方案1】:

    路径动画在 WWDC 会议 237 (Building Custom Views with SwiftUI) 中展示。关键是使用AnimatableData。您可以跳到 31:23,但我建议您至少在 27:47 分钟开始。

    您还需要下载示例代码,因为方便地,演示文稿中没有显示(也没有解释)有趣的部分:https://developer.apple.com/documentation/swiftui/drawing_and_animation/building_custom_views_in_swiftui


    更多文档: 由于我最初发布了答案,因此我继续研究如何为 Paths 设置动画,并发布了一篇文章,详细解释了 Animatable 协议以及如何将其与 Paths 一起使用:https://swiftui-lab.com/swiftui-animations-part1/


    更新:

    我一直在使用形状路径动画。这是一个 GIF。

    这是代码:

    重要提示:代码不会在 Xcode 实时预览中生成动画。它需要在模拟器或真机上运行。

    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 }
        }
    }
    

    【讨论】:

    • 还要确保你坚持到最后,他们解释了如何通过使用 Metal 设置绘图组来显着提高性能。
    • 我更新了我的答案以包含一个环形动画的工作示例。
    • 我又做了一次更新。不再需要使用 DispatchQueue 来创建多个动画。它现在只使用一个。
    • 我将代码复制到项目中的一个新文件中,我可以看到绿色圆圈但没有动画(与您发布的 GIF 不同)。有什么我想念的吗?谢谢!
    • 我在 SwiftUI 的第 2 天停止使用实时预览。我无法相信它,而是结束了浪费时间。我想我会等到 GM。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 2017-04-25
    • 2020-01-29
    • 2013-09-08
    • 1970-01-01
    • 2011-05-10
    • 1970-01-01
    相关资源
    最近更新 更多