Fixing weird shadow animation glitch in SwiftUI
My “glow” animation started going wrong when switching tabs in a tab bar.
Published: Nov. 15, 2023 Sponsored App StoreRecently in a work project I was working on a SwiftUI view with prominent part that had “glow effect” animation that I built with the shadow
modifier and the standard SwiftUI animations. Looked great. However I noticed that whenever I would switch tab in the UIKit tab bar and return to this screen, the animation would go wrong.
What was fascinating about it is that it basically always went wrong in the same way. Parts of the glow would appear clipped somehow in alternating pattern. Even though there is no clipping and I used frame
to give it minimal size way bigger than the circle to make sure no clipping could occur.
Next was trying to reset the animations on tab switch, which is apparently done by setting the animated properties to their default values and then restarting the animation with withAnimation
block. This curiously also did not help. Even when I waited a couple of seconds before starting the animation again.
Of course searching for “glow animation glitch” online went nowhere 😄 Maybe I choose the wrong terms, because I doubt I am the first one to run into issues with animating shadows.
What saved me in the end was the id
modifier. I basically created @State
property of type UUID
that I would use as the .id
modifier on the entire view that was being animated. And each time the UIHostingController
appeared again which indicated tab bar switching, I would just create new UUID
which would force SwiftUI do discard the previously animated view and create a new one, since its id was different.
And boom! Problem solved. I tried really hard to reproduce the issue again but couldn’t.
Here is very simplified version of what I did:
struct MyContainerView: View {
@State private var animationStateId = UUID()
var body: some View {
VStack {
CustomViewWithGlowAnimation()
.id(animationStateId)
// more views...
}
.onReceive(NotificationCenter.default.publisher(for: Notification.Name("resetGlowAnimation"), perform: { _ in
self.animationStateId = UUID()
})
}
}
And then I can just use NotificationCenter.default
to send the “resetGlowAnimation” notification whenever I need to make sure the animation is animating properly.
If you know about better solution, I am happy to hear it.