I don't often understand when SwiftUI resets the state of a view (i.e. all that is marked with @State). For example, take a look at this minimum example:
import SwiftUI
struct ContentView: View {
@State private var isView1Active = true
let view1 = View1()
let view2 = View2()
var body: some View {
VStack {
if isView1Active {
view1
} else {
view2
}
Button(action: {
self.isView1Active.toggle()
}, label: {
Text("TAP")
})
}
}
}
struct View1: View {
@State private var text = ""
var body: some View {
TextField("View1: type something...", text: $text)
}
}
struct View2: View {
@State private var text = ""
var body: some View {
TextField("View2: type something...", text: $text)
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
I'd want the two TextField
to keep their content, but if you run this example some weird behaviours occur:
View1
TextField
content persists:So, what's happening here? Is there a way to tell SwiftUI not to reset @State for a view? Thanks.
The issue is that View1
and View2
are being recreated every time isView1Active
is changed (because it is using @State
which reloads the body of ContentView
).
A solution would be to keep the text properties of the TextField
s in the ContentView
as shown below and use @Binding
:
struct ContentView: View {
@State private var isView1Active = true
@State private var view1Text = ""
@State private var view2Text = ""
var body: some View {
VStack {
if isView1Active {
View1(text: $view1Text)
} else {
View2(text: $view2Text)
}
Button(action: {
self.isView1Active.toggle()
}, label: {
Text("TAP")
})
}
}
}
struct View1: View {
@Binding var text: String
var body: some View {
TextField("View1: type something...", text: $text)
}
}
struct View2: View {
@Binding var text: String
var body: some View {
TextField("View2: type something...", text: $text)
}
}
Shown in action:
It view1
and view2
are completely independent and enclosure, like there is no contextmenu
or sheet
, you may use ZStack
and opacity
combinations.
var body: some View {
VStack {
ZStack{
if isView1Active {
view1.opacity(1)
view2.opacity(0)
} else {
view1.opacity(0)
view2.opacity(1)
}}
Button(action: {
self.isView1Active.toggle()
}, label: {
Text("TAP")
})
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With