SwiftUI | Animer cette forme de chemin
J'ai le cas suivant:
Je veux inverser cette forme avec une animation personnalisée. Je ne sais pas comment le décrire correctement.
Chaque fois que je tape sur la flèche, elle doit se transformer en une autre. Sans retourner, tourner, etc., simplement transformer.
Si ce n'est pas assez précis, n'hésitez pas à commenter!
Code démo
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)
}
}
Comme vous pouvez le voir maintenant, il n'a pas d'animation. Je ne sais pas comment faire.
Toute aide est très appréciée. Merci!
Remarque: je ne peux pas faire cela avec deux rectangles arrondis + simplement en rotation, car j'ai une animation d'opacité, ce qui rend le chevauchement visible.
Réponses
Voici une approche possible - déplacez le chemin dans une forme personnalisée et faites du paramètre modifié comme propriété animable. Testé avec Xcode 12 / iOS 14
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)
.animation(.default)
.onTapGesture { change.toggle() }
.padding(.top, 300)
}
}