I know there are a few frameworks out there that do this through more complicated means. But I am curious whether there is a way to do this in general, which is easier to set up.
In my case, I am trying to replicate .symbolEffect(.bounce, value: bounce)
but for an arbitrary view.
The problem with this is that normally if I wanted that, I would have a modifier on my view like .scaleEffect(bounce ? 1 : 1.2)
and then perhaps some sort of spring animation like .animation(.interpolatingSpring(stiffness: 350, damping: 5, initialVelocity: 10), value: bounce)
.
The problem, of course, is that this animation does not end where it started. So, at the end of the animation, I would end up with the scale being 1.2, which was not the goal. I could, of course, create a Task that, after a delay, sets bounce back to false, but that would trigger a spring animation back to 1.0.
Even if I did balance everything correctly, the animation would not look nearly as good as .symbolEffect(.bounce, value: bounce)
Is there any sort of repeatable way to have a spring animation end where it started?
phaseAnimator
does exactly that - it resets to the initial phase after all phases have been animated.
You can set up two phases - one for scaleEffect(1)
and one for scaleEffect(1.2)
It also takes an animation:
parameter, which allows you to specify an Animation
to use for each phase. In the below example, I used .spring.speed(2)
for both phases.
@State private var trigger = false
var body: some View {
Circle().frame(width: 100)
.phaseAnimator([false, true], trigger: trigger) { view, phase in
view.scaleEffect(phase ? 1.2 : 1)
} animation: { _ in .spring.speed(2) }
Button("Trigger") {
trigger.toggle()
}
}