Starting from this example: Two views in a VStack, coming and going with a different transition:
struct ContentView: View {
@State var value = false
var body: some View {
VStack {
ZStack {
value ? Color.red : Color.green
VStack {
Text(String(describing: value))
Button("Toggle") {
value.toggle()
}
}
}
.id(value)
.transition(.move(edge: .leading))
ZStack {
value ? Color.yellow : Color.orange
Text(String(value))
}
.frame(height: 200)
.id(value)
.transition(.move(edge: .bottom))
}
.animation(.easeInOut, value: self.value)
}
}
This works fine. Now, what surprised me is this: When you move out the .id
-modifier ("replace the outer view"), the inner views don't do the transitions any more:
struct ContentView: View {
@State var value = false
var body: some View {
VStack {
ZStack {
value ? Color.red : Color.green
VStack {
Text(String(describing: value))
Button("Change") {
value.toggle()
}
}
}
// .id(value) <-- not here
.transition(.move(edge: .leading))
ZStack {
value ? Color.yellow : Color.orange
Text(String(value))
}
.frame(height: 200)
// .id(value) <-- not here
.transition(.move(edge: .bottom))
}
.id(value) // <-- moved here
.animation(.easeInOut, value: self.value)
}
}
This seems to be how transitions work in the SwiftUI, it seems the transition must go on the View node that's replaced. If a View with a transition comes and goes because its parent View comes and goes, this doesn't trigger the transition.
To clarify the example, here is the same example without using .id()
where a container view wants parts of its content to come and go with a transition:
struct View1: View {
@Binding var value: Bool
var body: some View {
VStack {
ZStack {
value ? Color.red : Color.green
VStack {
Text(String(describing: value))
Button("Change") {
value.toggle()
}
}
}
.transition(.move(edge: .leading))
ZStack {
value ? Color.yellow : Color.orange
Text(String(value))
}
.frame(height: 200)
.transition(.move(edge: .bottom))
}
}
}
struct View2: View {
@Binding var value: Bool
var body: some View {
Button("Change") {
value.toggle()
}
}
}
struct ContentView: View {
@State var value = false
var body: some View {
ZStack {
if value {
View1(value: $value)
} else {
View2(value: $value)
}
}
.animation(.easeInOut, value: self.value)
}
}
Question: Is it possible to add transitions to inner views in SwiftUI that are triggered by replacing the outer View? (as in: can the last example have transitions while keeping View1/View2 separate/without being sneaky with the View hierarchy?)