I have the following case:

I want to flip this shape with a custom animation. I don't know how to describe it properly.
Whenever I tap on the arrow, it should transform into the other one. Without flipping, rotating, etc. just simply transforming.
If that's not precise enough, feel free to comment!
struct ContentView: View {
    
    @State private var change = false
    
    private let arrowWidth: CGFloat = 80
    
    
    var body: some View {
        Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: arrowWidth/2, y: change ? -20 : 20))
            path.move(to: CGPoint(x: arrowWidth/2, y: change ? -20 : 20))
            path.addLine(to: CGPoint(x: arrowWidth, y: 0))
        }
        .stroke(style: StrokeStyle(lineWidth: 12, lineCap: .round))
        .frame(width: arrowWidth)
        .foregroundColor(.green)
        .animation(.default)
        .onTapGesture { change.toggle() }
        .padding(.top, 300)
    }
}
As you can see now it has no animation. I have no idea how to do it.
Any help is much appreciated. Thanks!
Note: I can't do this with two rounded rectangles + simply rotating, since I have an opacity animation, which makes the overlapping visible.
Here is possible approach - move path into custom shape and make changed parameter as animatable property.

struct MyArrow: Shape {
    var width: CGFloat
    var offset: CGFloat
    
    var animatableData: CGFloat {
        get { offset }
        set { offset = newValue }
    }
    
    func path(in rect: CGRect) -> Path {
        Path { path in
            path.move(to: .zero)
            path.addLine(to: CGPoint(x: width/2, y: offset))
            path.move(to: CGPoint(x: width/2, y: offset))
            path.addLine(to: CGPoint(x: width, y: 0))
        }
    }
}
struct ContentView: View {
    
    @State private var change = false
    
    private let arrowWidth: CGFloat = 80
    
    
    var body: some View {
        MyArrow(width: arrowWidth, offset: change ? -20 : 20)
        .stroke(style: StrokeStyle(lineWidth: 12, lineCap: .round))
        .frame(width: arrowWidth)
        .foregroundColor(.green)
        .contentShape(Rectangle())
        .onTapGesture { withAnimation { change.toggle() } }
        .onTapGesture { change.toggle() }
        .padding(.top, 300)
    }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With