so I'm trying to show different elements in different ways when a view is presented in SwiftUI (One is a slide in from the leading edge and the other element is a slide up from the bottom of the screen). My basic view structure is as follows:
struct ViewName: View {
@ObservedObject var appState: AppState //this is just a class that tracks the state of app variables, in my case it holds a variable called 'showView' that indicates whether or not to show the view.
var body: some View {
ZStack {
Color.white
.edgesIgnoringSafeArea(.all)
VStack {
Text("Test")
}.transition(AnyTransition.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
VStack {
Spacer()
HStack {
Text("Test2")
Spacer()
Text("Test3")
}
}.transition(AnyTransition.move(edge: .bottom))
}
}
}
Elsewhere, I have the view initialized with something like:
if appState.showView {
ViewName(appState: appState)
}
and a button that changes whether the view is presented:
Button(action: {
withAnimation {
appState.showView.toggle()
}
}, label: {
Text("Click me")
})
It seems like Swift doesn't know what to do with the two transitions though, and it sort of defaults them both to a fade-in opacity transition. Not sure how to fix this. Any help much appreciated!
The problem is that you only have 1 if appState.showView {
.
if appState.showView {
ViewName(appState: appState)
}
As a result, SwiftUI only animates the entire ViewName
in and out, with the default fade transition (because you didn't specifify one).
Instead, you need to use if appState.showView {
on each separate element that you want to animate.
class AppState: ObservableObject {
@Published var showView = false
}
struct ContentView: View {
@StateObject var appState = AppState()
var body: some View {
VStack {
Button(action: {
withAnimation {
appState.showView.toggle()
}
}, label: {
Text("Click me")
})
ViewName(appState: appState) /// just make this always showing
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.green)
}
}
struct ViewName: View {
@ObservedObject var appState: AppState
var body: some View {
ZStack {
if appState.showView { /// need this, so `ViewName` will be invisible when `appState.showView` is false
Color.white
.edgesIgnoringSafeArea(.all)
/// optional: add a transition here too
/// by default, it will fade
}
if appState.showView { /// need this!
VStack {
Text("Test")
}
.zIndex(1) /// needed for removal transition
.transition(AnyTransition.asymmetric(insertion: .move(edge: .leading), removal: .move(edge: .trailing)))
}
if appState.showView { /// need this!
VStack {
Spacer()
HStack {
Text("Test2")
Spacer()
Text("Test3")
}
}
.zIndex(2) /// needed for removal transition
.transition(AnyTransition.move(edge: .bottom))
}
}
}
}