I'm running into a problem where it's difficult to use explicit animation for a particular state change, and I'd like to rely on SwiftUI implicit animation using a AnimatableModifier. Example code below to show a rotation flip effect.
When I trigger the state change using withAnimation call I get the expected animation that shows the flip happening when the view object is rotated by 90 degrees.
When I rely on implicit animation modifier of the view "flips" earlier - at somewhere around 45-60.
Not sure if I'm using AnimatableModifier wrong or it cannot be used implicitly?
struct ContentView: View {
@State var implicitPressed: Bool = false
@State var explicitPressed: Bool = false
var body: some View {
VStack {
Text("Implicit")
FlippedRectangle(isPressed: $implicitPressed)
.onTapGesture {
implicitPressed.toggle()
}
.animation(.easeInOut(duration: 3))
Text("Explicit")
FlippedRectangle(isPressed: $explicitPressed)
.onTapGesture {
withAnimation(.easeInOut(duration: 3)) {
explicitPressed.toggle()
}
}
}
}
}
struct FlippedRectangle: View {
@Binding var isPressed: Bool
var body: some View {
ZStack {
RoundedRectangle(cornerRadius: 25.0)
.fill(Color.blue)
.modifier(FlipModifer(angle: isPressed ? 180 : 0, reversed: true))
RoundedRectangle(cornerRadius: 25.0)
.fill(Color.green)
.modifier(FlipModifer(angle: isPressed ? 180 : 0))
}
.frame(width: 150, height: 200)
}
}
struct FlipModifer: AnimatableModifier {
var angle: Double
var zIndex: Double = 0
var reversed: Bool = false
var animatableData: Double {
get {
angle
}
set {
self.angle = newValue
self.zIndex = (newValue < 90) ? (reversed ? -1 : 0) : (reversed ? 0 : -1)
}
}
private var rotation: Angle { Angle.degrees(angle) + ( reversed ? .degrees(180) : .degrees(0)) }
func body(content: Content) -> some View {
content
.rotation3DEffect(rotation, axis: (x: 0.0, y: 1.0, z: 0.0))
.zIndex(zIndex)
}
}

