带数组的 SwiftUI 动画形状

标签 swift animation swiftui

我正在尝试在 SwiftUI 中对从对象数组中的数据派生的自定义形状进行动画处理。我创建此示例是为了说明我在尝试使其正常工作时遇到的问题。

在这个简单的例子中。拖动红点后,它会通过 Spring 动画偏移其 X 和 Y。然而,形状会捕捉到新位置,而不是用点平滑地设置动画。

我已经在 animatableData 上尝试了多个版本,但仍然无法使动画正常工作。希望对此有更了解的人帮忙!谢谢。

enter image description here

final class Item: Identifiable {
    let id: String
    var position: CGPoint
    
    let radius: CGFloat = 10
    var offset: CGSize {
        CGSize(width: position.x-radius, height: position.y-radius)
    }
    
    init(id: String, position: CGPoint) {
        self.id = id
        self.position = position
    }
}

final class Manager: ObservableObject {
    var items = [
        Item(id: "Item 1", position: .init(x: 50, y: 200)),
        Item(id: "Item 2", position: .init(x: 200, y: 200)),
        Item(id: "Item 3", position: .init(x: 200, y: 50))
    ]
}

struct CustomShape: Shape {
    @ObservedObject var manager: Manager
    
    var animatableData: [Item] {
        get { manager.items }
        set { manager.items = newValue }
    }
    
    func path(in rect: CGRect) -> Path {
        Path { path in
            for i in 0..<animatableData.count {
                let item = animatableData[i]
                if i == 0 {
                    path.move(to: item.position)
                } else {
                    path.addLine(to: item.position)
                }
            }
        }
    }
}

struct ContentView: View {
    @ObservedObject var manager = Manager()
    
    var body: some View {
        ZStack(alignment: .topLeading) {
            CustomShape(manager: manager)
            
            ForEach(manager.items) { item in
                Circle().foregroundColor(.red)
                    .frame(width: item.radius*2, height: item.radius*2)
                    .offset(item.offset)
                    .gesture(
                        DragGesture()
                            .onChanged { gesture in
                                manager.objectWillChange.send()
                                item.position = gesture.location
                            }
                            .onEnded { gesture in
                                withAnimation(.spring()) {
                                    manager.objectWillChange.send()
                                    item.position = CGPoint(
                                        x: item.position.x + 20,
                                        y: item.position.y + 20
                                    )
                                }
                            }
                    )
            }
        }
    }
}

最佳答案

您在animatableData中指定的项目本身必须是可动画的,即符合Animatable协议(protocol)。这包括 CGPoint 、CGRect 、CGSize 和其他一些类型。或者它们必须符合 VectorArithmetic 协议(protocol),其中还包括 FloatCGFloatDoubles。如果您在 GitHub 上搜索“animatableData”,您应该能够找到各种示例。

关于带数组的 SwiftUI 动画形状,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62864026/

相关文章:

ios - 属性(property)观察员及其行为

android - 在动画android期间获取imageview的坐标

swiftui - 如何在 SwiftUI 中对 Imagepicker 进行两次单独调用?

ios - 获取图像时出错

swift - EXC_BREAKPOINT -- 由使用 swift spritekit 的碰撞检测引起

objective-c - 带有动画的 iOS 方法调用,完成时执行操作?

iphone - 建立一个漂亮的进度条

ios - SwiftUI:NavigationLink 的目标 View 的异构集合?

swift - @State var 仅在单击第二个按钮后更改 SwiftUI

objective-c - 如何将自定义 NSView 添加到使用 Interface Builder 构建的 UI?