Reputation: 1289
I'd like to make a custom view transition in SwiftUI, animated in 2 steps:
Presenting child
Dismissing child
Demo (created artificially)
Base code:
struct TransitionTestView: View {
@State var presented = false
var body: some View {
ZStack {
if presented {
Button("Hide", action: { presented = false })
.foregroundColor(.black)
.font(.largeTitle)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.purple)
}
else {
Button("Show", action: { presented = true })
.foregroundColor(.black)
.font(.largeTitle)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.orange)
}
}
.padding(30)
}
}
I've experimented with:
animation
modifier: to the ZStack, or to each element individually.opacity.animation(.linear(duration: 1).delay(1))
But I couldn't make it work. Any help appreciated, thanks a lot!
Upvotes: 0
Views: 569
Reputation: 257533
A possible approach can be using transaction transformation by injecting additional delay to main animation for each phase.
Tested with Xcode 13.4 / iOS 15.5
Main part:
ZStack {
VStack { // << animating container
if presented {
Button("Hide", action: { presented = false })
.foregroundColor(.black)
.font(.largeTitle)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.purple)
.transition(.move(edge: .bottom))
}
}
.transaction { // << transform animation for direct transition
$0.animation = $0.animation?.delay(presented ? 1.2 : 0)
}
VStack { // << animating container
if !presented {
Button("Show", action: { presented = true })
.foregroundColor(.black)
.font(.largeTitle)
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.orange)
.transition(.opacity)
}
}
.transaction { // << transform animation for reverse transition
$0.animation = $0.animation?.delay(presented ? 0 : 1.2)
}
}
.animation(.linear(duration: 1), value: presented) // << main !!
Upvotes: 2