SwiftUI-动画路径形状笔画

时间:2020-05-26 11:09:22

标签: ios swift animation path swiftui

每当路径的终点发生变化时,是否有办法使路径的笔划动画化?

这是我的代码的片段:

struct JourneyMapLineView: View {        
    @Binding var rects: [CGRect]

    var body: some View {
        rects.count != 0 ?
            JourneyMapLineShape(startRect: rects[0], endRect: rects[rects.count-1])
                .stroke(Color.red), lineWidth: 8)
                .animation(.easeInOut(duration: 0.3)) //<-- Is not working
        : nil
    }
}

struct JourneyMapLineShape: Shape {
    var startRect: CGRect
    var endRect: CGRect

    func path(in _: CGRect) -> Path {
        var path = Path()

        path.move(to: startRect.origin)
        path.addLine(to: endRect.origin)

        return path
    }
}

如您所见,当前,通过更改endRect的值没有动画:

enter image description here

我已经看过一些类似的问题,看来这是一个新情况。

非常感谢您!

1 个答案:

答案 0 :(得分:1)

这里是可能解决方案的演示。使用Xcode 11.4 / iOS 13.4进行了测试

demo

// Route shape animating head point
struct Route: Shape {
    var points: [CGPoint]
    var head: CGPoint

    // make route animatable head position only
    var animatableData: AnimatablePair<CGFloat, CGFloat> {
        get { AnimatablePair(head.x, head.y) }
        set {
            head.x = newValue.first
            head.y = newValue.second
        }
    }

    func path(in rect: CGRect) -> Path {
        Path { path in
            guard points.count > 1 else { return }
            path.move(to: points.first!)
            _ = points.dropFirst().dropLast().map { path.addLine(to: $0) }
            path.addLine(to: head)
        }
    }
}

// Route view model holding all points and notifying when last one changed
class RouteVM: ObservableObject {
    var points = [CGPoint.zero] {
        didSet {
            self.lastPoint = points.last ?? CGPoint.zero
        }
    }
    @Published var lastPoint = CGPoint.zero
}

struct DemoRouteView: View {
    @ObservedObject var vm = RouteVM()

    var body: some View {
        GeometryReader { gp in
            ZStack { // area
                Rectangle().fill(Color.white)
                    .gesture(DragGesture(minimumDistance: 0).onEnded { value in
                        self.vm.points.append(value.location) // read coordinates in area
                    })

                Circle().fill(Color.blue).frame(width: 20)
                    .position(self.vm.points.first!) // show initial point

                // draw route when head changed, animating
                Route(points: self.vm.points, head: self.vm.lastPoint)
                    .stroke(style: StrokeStyle(lineWidth: 8, lineCap: .round, lineJoin: .miter, miterLimit: 0, dash: [], dashPhase: 0))
                    .foregroundColor(.red)
                    .animation(.linear(duration: 0.5))
            }
            .onAppear {
                let area = gp.frame(in: .global)
                // just initail point at the bottom of screen
                self.vm.points = [CGPoint(x: area.midX, y: area.maxY)]
            }
        }.edgesIgnoringSafeArea(.all)
    }
}