I am building a custom tab bar in SwiftUI. The views are attached to tab bar buttons and load without any issues. But the data stored in the @State variable in the screen resets while tapping on the button.
struct ContentView: View {
@State var index = 0
let tabs: [AnyView]
init() {
print("### Contentview initialized ")
tabs = [AnyView(WelcomeView(count: 0)),
AnyView(ProfileScreen(count: 0))]
}
var body: some View {
VStack(spacing: 0) {
ZStack {
tabs[index]
}
CustomTabbar(index: self.$index)
}
.navigationBarBackButtonHidden(true)
}
}
struct CustomTabbar: View {
@Binding var index: Int
var body: some View {
HStack(alignment: .bottom) {
Button(action: {
self.index = 0
}) {
VStack(spacing: 6) {
Image(systemName: "house")
Text("Welcome")
.font(.system(size: 12))
}
.foregroundColor(index == 0 ? .blue : .black)
}
Spacer(minLength: 15)
Button(action: {
self.index = 4
}) {
VStack(spacing: 6) {
Image(systemName: "person")
Text("My Profile")
.font(.system(size: 12))
}
.foregroundColor(index == 4 ? .blue : .black)
}
}
.frame(height: 50)
.padding(.horizontal, 25)
.background(Color.white)
}
}
struct WelcomeView: View {
@State private var count: UInt = 0
@State private var firstAppear = false
init(count: UInt, firstAppear: Bool = false) {
print("WelcomeView init")
self.count = count
self.firstAppear = firstAppear
}
var body: some View {
VStack {
Spacer()
Text("Welcome view")
Spacer()
}.onAppear {
count += 1
print("WelcomeView appear",count)
}
}
}
struct ProfileScreen: View {
@State private var count: UInt = 0
init(count: UInt) {
print("profile screen init")
self.count = count
}
var body: some View {
VStack {
Spacer()
Text("Profile screen")
Spacer()
}.onAppear {
count += 1
print("Profile view appear",count)
}
}
}
Whenever the tab button is clicked, the count in that view resets to 0, but the init method is called once. Why is this happening? How can I preserve the state variable during the tab switch?
TIA
2
Answers
It has been a while since I used swift UI, but I believe the issue is the fact that you use
tabs[index]
in order to switch between components. Although you are creating a single instance of each view, the view’s body does not behave like a single instance. @State is not persistent between renders, hence the state disappears. You should hoist the variables into theContentView
and use a binding to make the state persistent since the ContentView will not need to rerender. Another solution is using something like MVVM in order to more professionally manage state in your application.This can help?