I have a TabView in my app that is meant to display four screens. Two are similar but have different data sources. If I click on the first tab (EventsScreen), and then the third tab (MyBagScreen) everything works fine. If I click on the first tab (EventsScreen) and then the second tab (EventsScreen), it just loads a blank screen (i presume it is only loading the background). They are two different objects, so why does this not work?
AppView.swift
struct AppView: View {
var body: some View {
TabView {
EventsScreen().environmentObject(EventsViewModel(repo: IncentivesRespository()))
.tabItem {
Text("Barter")
Image("icon_barter")
}
EventsScreen().environmentObject(EventsViewModel(repo: OpportunityRepository()))
.tabItem {
Text("Earn")
Image("icon_earn")
}
MyBagScreen().environmentObject(MyBagViewModel())
.tabItem{
Text("My Bag")
Image("icon_bag")
}
AccountScreen().environmentObject(AccountViewModel())
.tabItem {
Text("Account")
Image("icon_account")
}
}
.onAppear(perform: {
UITabBar.appearance().backgroundColor = .black
})
.navigationBarHidden(true)
}
}
EventsScreen
struct EventsScreen: View {
@EnvironmentObject
var viewModel: EventsViewModel
let calendarManager = RKManager(calendar: Calendar.current, minimumDate: Date(), maximumDate: Date().addingTimeInterval(60*60*24*90), mode: 1)
@State
var currentPage: Int = 0
@State
private var searchTerm : String = ""
init() {
UITableView.appearance().separatorStyle = .none
}
var body: some View {
GeometryReader { geometry in
List {
ZStack(alignment: .top) {
EventViewController(controllers: self.viewModel.featureEventControllers, currentPage: self.$currentPage)
VStack {
SearchBar(text: self.$searchTerm)
.padding(EdgeInsets.init(top: 16, leading: 16, bottom: 0, trailing: 16))
HStack {
Spacer()
Chip(text: "Dates", action: {
self.viewModel.showDateSelection.toggle()
})
.sheet(isPresented: self.$viewModel.showDateSelection, onDismiss: {
self.viewModel.onDatesSelected(startDate: self.calendarManager.startDate, endDate: self.calendarManager.endDate)
}, content: {
RKViewController(isPresented: self.$viewModel.showDateSelection, rkManager: self.calendarManager)
})
Chip(text:"Type", action: {
self.viewModel.showTypeSelection.toggle()
})
Chip(text: "Points", action: {
self.viewModel.showPointsSelection.toggle()
})
Spacer()
}
}
}.listRowInsets(EdgeInsets())
.frame(height: 600)
ForEach(self.viewModel.eventSections.indices) { id in
EventSectionView(eventSection: self.viewModel.eventSections[id])
}
.listRowBackground(Color.black)
}
.navigationBarTitle(Text("Events"), displayMode: .inline)
.navigationBarHidden(true)
if self.viewModel.showPointsSelection {
EventsPointsRangeBottomSheet(isOpen: self.$viewModel.showPointsSelection, selectedRange: self.$viewModel.selectedRange, range: 0.0...self.viewModel.maxPoints, action: {
self.viewModel.onPointsSelected()
})
}
if self.viewModel.showTypeSelection {
TypeBottomSheet(categories: self.viewModel.allCategories, isOpen: self.$viewModel.showTypeSelection, selectedCategoryUuids: self.$viewModel.selectedCategoryUuids, action: {
self.viewModel.onTypesSelected()
})
}
}
}
}
Your code snapshot is not testable, so just an idea - you have to test it itself.
So, assuming that your environment object for second view is correct, try to to make those to views really unique by using .id
modifier, like below
TabView {
EventsScreen().environmentObject(EventsViewModel(repo: IncentivesRespository()))
.id(1) // << here !!
.tabItem {
Text("Barter")
Image("icon_barter")
}
EventsScreen().environmentObject(EventsViewModel(repo: OpportunityRepository()))
.id(2) // << here !!
.tabItem {
Text("Earn")
Image("icon_earn")
}
...
Note: I see usage .navigationBarHidden(true)
in AppView
- if it means you are going to include TabView
into NavigationView
, then don't do that - you won't have it work. TabView is designed to be root view only. If you need navigation place it inside tabs.
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