What works so far
In a game I am displaying a number to the user with some code like this:
Text("\(model.product)")
I want Text
to have an interesting transition happen each time model.product
changes. To arrange this I've used the id
hack:
Text("\(model.product)")
.id(model.product)
// Transition here is included at the end of the post.
.transition(.explodeUp)
So now, in effect, each time the model.product
changes, any existing Text
showing the old product
is removed (with a transition) and a new Text
view is inserted to show the new product
(with a transition).
So far, this works nicely, I've got my Transition
all tweaked up, and it's a pretty nice effect [attached at the end]. Cool bananas!
What I want though
While this is nice as it is, not all model.product
changes are alike…
The existing code uses the same transition regardless of how product.model
has changed. What I want is for the transition used to depend on how product.model
has changed.
FWIW, I actually want to vary the transition depending on why
product.model
has changed, but I can accomplish this in the model I think, so it seems unimportant to the SwiftUI side.
The current transition is great for when the number increases. I want to use something else if the number decreases (probably called AnyTransition.dropDown
or something).
I'd like to be able to look at the old and new values of model.product
and choose between two different transitions depending on whether the value has increased or decreased.
Looking at the Transition
protocol, and Transaction
, this seems like it probably ought to be possible to do this.
I think I'd certainly want to stop using the id
hack. Instead perhaps I could have an extension on View
which would read like this at the usage site…
Text(model.product)
.replacingWithTransitionOnChanges(of: model.product) { oldValue, newValue in
oldValue < newValue ? .explodeUp : .dropDown
}
And the extension declaration would perhaps look like this:
extension View {
func replacingWithTransitionOnChanges<Value: Hashable>(
of value: Value,
_ transitionSource: (Value, Value) -> some Transition
) {
// What in the name of fish cakes goes in here though? :-/
}
}
But as you see, I've got not a lot of an idea how I'd build the function. Yet?
Any ideas for that? Or else – perhaps there are really easy ways to get this effect that I'm not thinking of?
Thanks!
The .explodeUp transition
My transition declaration, if anyone is interested…
extension AnyTransition {
static var explodeUp: AnyTransition {
.asymmetric(
insertion: .scale(scale: 0.5)
.combined(with: .opacity)
.animation(.easeInOut(duration: 0.2)),
removal: .scale(scale: 1.8)
.combined(with: .opacity)
.combined(with: .rotate(angle: .degrees(Double.random(in: -20..<20))))
.animation(.easeInOut(duration: 0.4))
)
}
static func rotate(angle: Angle) -> AnyTransition {
.modifier(active: RotateModifier(angle: angle), identity: RotateModifier(angle: .zero))
}
}