每当路径的终点发生变化时,是否有办法使路径的笔划动画化?
这是我的代码的片段:
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
的值没有动画:
我已经看过一些类似的问题,看来这是一个新情况。
非常感谢您!
答案 0 :(得分:1)
这里是可能解决方案的演示。使用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)
}
}