I want to create some sort of banner view that either moves in or out with animations when some state changes in SwiftUI. It feels like a basic task to do but the transition when showing the banner is not being animated. Hiding works fine.
So for demonstration purposes, here is a basic view modifier that creates a ZStack
with the content and a conditional view that acts as the banner overlay and has a transition:
struct BannerViewModifier: ViewModifier {
let showBanner: Bool
func body(content: Content) -> some View {
ZStack {
content
if showBanner {
VStack {
Text("banner")
Spacer()
}.transition(.move(edge: .top).combined(with: .opacity))
}
}
}
}
If I would then go ahead and tack that view modifier onto a button that toggles a boolean like this (with explicit animations)...
@State var showBanner = false
var body: some View {
Button(showBanner ? "Hide banner" : "Show banner") {
withAnimation { showBanner.toggle() }
}.modifier(BannerViewModifier(showBanner: showBanner))
}
... it results in not animating the show transition as I already mentioned.
Solutions I've tried already:
When adding an implicit animation to the VStack
with the transition modifier like this:
.animation(.default).transition(.move(edge: .top).combined(with: .opacity))
the show animation works.
However this feels like bad practice since the user of the view modifier cannot control the animation properties since they are baked into the view modifier already. Furthermore the animation modifier .animation(.default)
was deprecated in iOS 15 and its replacement .animation(.default, value: showBanner)
also does not animate the show transition either.