Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does TabView shows blank screen if two views are the same?

Tags:

ios

swift

swiftui

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()
                })
            }

        }
    }
}
like image 469
Adrian Le Roy Devezin Avatar asked Mar 21 '20 21:03

Adrian Le Roy Devezin


1 Answers

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.

like image 98
Asperi Avatar answered Oct 31 '22 10:10

Asperi