I have a view that uses the .matchedGeometryEffect
to make moving transitions. I'd like to be able to switch this effect off if the user objects to this type of animation.
I could create two almost identical views, one with the .matchedGeometry modifier and one without, and invoke either of them using an @AppStorage parameter. However, I'm hoping there's a more elegant way of disabling the modifier.
Example code here for matchedGeometry here: SwiftUI: Creating a custom segmented control using .matchedGeometry()
I found a promising article from TwoStraws but I cannot specify .matchedGeometryEffect
instead of .linear
as a type of animation like this:
Button("Ping pong") {
var transaction = Transaction(animation: .matchedGeometryEffect)
transaction.disablesAnimations = true
withTransaction(transaction) {
isFlipped.toggle()
}
}
Error message:
Type 'Animation?' has no member '_MatchedGeometryEffect'
Is there any other way to disable the .matchedGeometryEffect or am I doomed to write 2 almost identical views?
One way to disable the matched geometry effect is to just pass different IDs to matchedGeometryEffect
. You can get unique IDs by doing UUID()
. This effectively turns off the matched geometry effect because none of the IDs match each other, but keeps the other animations the same.
Here is a simple example:
struct ContentView: View {
@Namespace var ns
@State private var toggle = false
@State private var enabled = true
var body: some View {
if toggle {
Circle().frame(width: 100)
// If the *intended* ID is not a UUID, use AnyHashable to erase both of their types
.matchedGeometryEffect(id: enabled ? AnyHashable("circle") : AnyHashable(UUID()), in: ns)
} else {
Circle().frame(width: 200)
.offset(x: 100)
.matchedGeometryEffect(id: enabled ? AnyHashable("circle") : AnyHashable(UUID()), in: ns)
}
Toggle("Enable Animation", isOn: $enabled)
Button("Play Animation") {
withAnimation {
toggle.toggle()
}
}
}
}
Of course, if you don't want any animation, use .animation(nil, value: ...)
as you normally would.