问题
Is there a way to animate the stroke drawing of a path whenever its destination point changes?
Here is a snippet of my code:
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
}
}
Currently, as you can see, there is no animation by changing the value of endRect
:
I have already looked at some similar questions, it seems that this is a new case,.
Thank you so much!
回答1:
Here is a demo of possible solution. Tested with Xcode 11.4 / iOS 13.4
// 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)
}
}
来源:https://stackoverflow.com/questions/62020789/swiftui-animate-path-shape-stroke-drawing