I'm trying to show different shapes as path animation after each other. The animation should start always from showing nothing to the finished shape.
My problem is that it's working just with the first shape, I think because of the onAppear
. However, after clicking the next button, the next shapes are not animating.
I tried playing with the pathProgress
value, and another boolean, but either it doesn't animate at all, or it animates backwards.
import SwiftUI
struct ContentView: View {
@State var id = 1
@State var pathProgress = 0.0
var body: some View {
VStack {
ConsonantDrawing(id: id)
.trim(from: 0, to: pathProgress)
.stroke(Color.red, style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
.animation(.linear(duration: 4.0), value: pathProgress)
.onAppear {
pathProgress = 1.0
}
.frame(width: UIScreen.main.bounds.width * 0.5, height: UIScreen.main.bounds.height * 0.5)
Spacer()
HStack {
Button {
id -= 1
} label: {
Image(systemName: "arrow.backward.circle")
}
Spacer()
Button {
id += 1
} label: {
Image(systemName: "arrow.forward.circle")
}
}
.padding()
.font(.largeTitle)
}
}
}
struct ConsonantDrawing: Shape {
var id: Int
func path(in rect: CGRect) -> Path {
var path = Path()
let width = rect.size.width
let height = rect.size.height
switch id {
case 1:
path.move(to: CGPoint(x: 0.12069*width, y: 0.97451*height))
path.addLine(to: CGPoint(x: 0.12069*width, y: 0.52102*height))
path.addCurve(to: CGPoint(x: 0.36207*width, y: 0.33497*height), control1: CGPoint(x: 0.12069*width, y: 0.38149*height), control2: CGPoint(x: 0.36207*width, y: 0.33497*height))
path.addCurve(to: CGPoint(x: 0.03448*width, y: 0.27684*height), control1: CGPoint(x: 0.2069*width, y: 0.28846*height), control2: CGPoint(x: 0.03448*width, y: 0.27684*height))
path.addCurve(to: CGPoint(x: 0.98276*width, y: 0.27684*height), control1: CGPoint(x: 0.03448*width, y: -0.02549*height), control2: CGPoint(x: 0.94828*width, y: -0.09526*height))
path.addLine(to: CGPoint(x: 0.98276*width, y: 0.97451*height))
case 2:
path.move(to: CGPoint(x: 0.04412*width, y: 0.24668*height))
path.addCurve(to: CGPoint(x: 0.27941*width, y: 0.19048*height), control1: CGPoint(x: 0.08154*width, y: 0.17525*height), control2: CGPoint(x: 0.20588*width, y: 0.15476*height))
path.addCurve(to: CGPoint(x: 0.35294*width, y: 0.34524*height), control1: CGPoint(x: 0.35294*width, y: 0.22619*height), control2: CGPoint(x: 0.38079*width, y: 0.28888*height))
path.addCurve(to: CGPoint(x: 0.20588*width, y: 0.42857*height), control1: CGPoint(x: 0.32353*width, y: 0.40476*height), control2: CGPoint(x: 0.26471*width, y: 0.42857*height))
path.addCurve(to: CGPoint(x: 0.04412*width, y: 0.32143*height), control1: CGPoint(x: 0.14706*width, y: 0.42857*height), control2: CGPoint(x: 0.05882*width, y: 0.40476*height))
path.addCurve(to: CGPoint(x: 0.07353*width, y: 0.15476*height), control1: CGPoint(x: 0.02941*width, y: 0.2381*height), control2: CGPoint(x: 0.05588*width, y: 0.19048*height))
path.addCurve(to: CGPoint(x: 0.35294*width, y: 0.04762*height), control1: CGPoint(x: 0.10294*width, y: 0.09524*height), control2: CGPoint(x: 0.23438*width, y: 0.04762*height))
path.addCurve(to: CGPoint(x: 0.63235*width, y: 0.19048*height), control1: CGPoint(x: 0.47059*width, y: 0.04762*height), control2: CGPoint(x: 0.60294*width, y: 0.08333*height))
path.addCurve(to: CGPoint(x: 0.57353*width, y: 0.39286*height), control1: CGPoint(x: 0.65523*width, y: 0.27381*height), control2: CGPoint(x: 0.61001*width, y: 0.34856*height))
path.addCurve(to: CGPoint(x: 0.47059*width, y: 0.58333*height), control1: CGPoint(x: 0.51471*width, y: 0.46429*height), control2: CGPoint(x: 0.47059*width, y: 0.53571*height))
path.addCurve(to: CGPoint(x: 0.47059*width, y: 0.83333*height), control1: CGPoint(x: 0.47059*width, y: 0.62143*height), control2: CGPoint(x: 0.47059*width, y: 0.78571*height))
path.addCurve(to: CGPoint(x: 0.98529*width, y: 0.83333*height), control1: CGPoint(x: 0.47059*width, y: 1.02381*height), control2: CGPoint(x: 0.95588*width, y: 1.04762*height))
path.addCurve(to: CGPoint(x: 0.98529*width, y: 0.0119*height), control1: CGPoint(x: 0.98529*width, y: 0.60714*height), control2: CGPoint(x: 0.98529*width, y: 0.19048*height))
case 3:
path.move(to: CGPoint(x: 0.03186*width, y: 0.38372*height))
path.addCurve(to: CGPoint(x: 0.27056*width, y: 0.27907*height), control1: CGPoint(x: 0.04505*width, y: 0.25581*height), control2: CGPoint(x: 0.19913*width, y: 0.25581*height))
path.addCurve(to: CGPoint(x: 0.34199*width, y: 0.44186*height), control1: CGPoint(x: 0.34199*width, y: 0.30233*height), control2: CGPoint(x: 0.36904*width, y: 0.38681*height))
path.addCurve(to: CGPoint(x: 0.17056*width, y: 0.51163*height), control1: CGPoint(x: 0.31341*width, y: 0.5*height), control2: CGPoint(x: 0.24198*width, y: 0.52326*height))
path.addCurve(to: CGPoint(x: 0.03186*width, y: 0.38372*height), control1: CGPoint(x: 0.09913*width, y: 0.5*height), control2: CGPoint(x: 0.04615*width, y: 0.46512*height))
path.closeSubpath()
path.move(to: CGPoint(x: 0.03186*width, y: 0.38372*height))
path.addCurve(to: CGPoint(x: 0.07056*width, y: 0.19767*height), control1: CGPoint(x: 0.01758*width, y: 0.30233*height), control2: CGPoint(x: 0.05341*width, y: 0.23256*height))
path.addCurve(to: CGPoint(x: 0.24198*width, y: 0.05814*height), control1: CGPoint(x: 0.09913*width, y: 0.13953*height), control2: CGPoint(x: 0.17056*width, y: 0.0814*height))
path.addCurve(to: CGPoint(x: 0.37056*width, y: 0.15116*height), control1: CGPoint(x: 0.29913*width, y: 0.09302*height), control2: CGPoint(x: 0.24198*width, y: 0.05814*height))
path.addCurve(to: CGPoint(x: 0.49913*width, y: 0.05814*height), control1: CGPoint(x: 0.49913*width, y: 0.05814*height), control2: CGPoint(x: 0.41341*width, y: 0.11628*height))
path.addCurve(to: CGPoint(x: 0.65627*width, y: 0.19767*height), control1: CGPoint(x: 0.61341*width, y: 0.09302*height), control2: CGPoint(x: 0.64413*width, y: 0.1532*height))
path.addCurve(to: CGPoint(x: 0.54615*width, y: 0.47674*height), control1: CGPoint(x: 0.67849*width, y: 0.27907*height), control2: CGPoint(x: 0.58159*width, y: 0.43348*height))
path.addCurve(to: CGPoint(x: 0.48484*width, y: 0.62791*height), control1: CGPoint(x: 0.5277*width, y: 0.49927*height), control2: CGPoint(x: 0.48484*width, y: 0.5814*height))
path.addCurve(to: CGPoint(x: 0.48484*width, y: 0.81395*height), control1: CGPoint(x: 0.48484*width, y: 0.66512*height), control2: CGPoint(x: 0.48484*width, y: 0.76744*height))
path.addCurve(to: CGPoint(x: 0.98484*width, y: 0.81395*height), control1: CGPoint(x: 0.48484*width, y: 1.02326*height), control2: CGPoint(x: 0.95627*width, y: 1.02326*height))
path.addCurve(to: CGPoint(x: 0.98484*width, y: 0.02326*height), control1: CGPoint(x: 0.98484*width, y: 0.59302*height), control2: CGPoint(x: 0.98484*width, y: 0.19767*height))
default:
path.move(to: CGPoint(x: 0.12069*width, y: 0.97451*height))
path.addLine(to: CGPoint(x: 0.12069*width, y: 0.52102*height))
}
return path
}
}
The issue is that you are not resetting pathProgress
. What I did was to reset it when pressing the back or next buttons and checking wheter the current id
was the first or the last one to avoid issue with animations.
I also removed the .animation
modifier on the ConsonantDrawing
view because it was causing issues and placed the animtion in the actions rather:
struct ContentView: View {
@State var id = 1
@State var pathProgress = 0.0
var body: some View {
VStack {
ConsonantDrawing(id: id)
.trim(from: 0, to: pathProgress)
.stroke(Color.red, style: StrokeStyle(lineWidth: 20, lineCap: .round, lineJoin: .round))
/// Remove this .animation line because is part of the issue!
//.animation(.linear(duration: 4.0), value: pathProgress)
.frame(width: UIScreen.main.bounds.width * 0.5, height: UIScreen.main.bounds.height * 0.5)
Spacer()
HStack {
Button {
guard id != 1 else { return }
id -= 1
pathProgress = 0
withAnimation(.linear(duration: 4)) {
pathProgress = 1.0
}
} label: {
Image(systemName: "arrow.backward.circle")
}
Spacer()
Button {
guard id != 3 else { return }
pathProgress = 0
id += 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
withAnimation(.linear(duration: 4)) {
pathProgress = 1.0
}
}
} label: {
Image(systemName: "arrow.forward.circle")
}
}
.padding()
.font(.largeTitle)
}
.onAppear {
print("On appear")
withAnimation(.linear(duration: 4)) {
pathProgress = 1.0
}
}
}
}
Here's the result:
Let me know how'd you find this soltution!