Форма анимации SwiftUI с массивом - PullRequest
1 голос
/ 12 июля 2020

Я пытаюсь анимировать пользовательскую форму в SwiftUI, полученную из данных в массиве объектов. Я создал этот образец, чтобы проиллюстрировать проблему, с которой я сталкиваюсь, пытаясь заставить это работать.

В этом простом примере. После перетаскивания красной точки она смещает свои 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
                                    )
                                }
                            }
                    )
            }
        }
    }
}

1 Ответ

0 голосов
/ 25 июля 2020

Элементы, которые вы указываете в animatableData, сами должны быть анимированными, ie должны соответствовать протоколу Animatable. Сюда входят CGPoint s, CGRect s, CGSize s и некоторые другие типы. Либо это, либо они должны соответствовать протоколу VectorArithmetic, в который также входят Float s, CGFloat s и Double s. Если вы выполните поиск на GitHub по запросу "animatableData", вы сможете найти всевозможные примеры.

...