0

My App requires an initial view to be loaded programatically and not via the TabView. Here is an MRE to show the problem. The sequence is:

  • ContentView loads the TabMenu
  • The initial TabMenu View is OneView
  • From the tabs you can switch between OneView and TwoView

How do I get the OneView to programatically load TwoView. It currently loses the Tab Menu (final screen shot below). In the full version of my code it was crashing to @main.

ContentView

import SwiftUI

struct ContentView: View {

@State var selectedTab = TabChoice.one
@State var calculated = CalculatedChoice.falseCC

var body: some View {
    NavigationStack {
        VStack {
            // MARK: BUTTON
            Spacer()
            NavigationLink(destination: MenuView().navigationBarBackButtonHidden(true))   {
                Text("Press to launch the TabView Menu")
                    .tint(.black)
            }
            Spacer()
        }
    }
    .padding()
}
}

#Preview {
    ContentView()
}

MenuView

import SwiftUI

enum TabChoice {
    case one, two
}

enum CalculatedChoice {
    case falseCC, trueCC
}

struct MenuView: View {

@State var selectedTab = TabChoice.one
@State var calculated = CalculatedChoice.falseCC

var body: some View {
    NavigationStack {
        VStack {
            TabView(selection: $selectedTab) {
                
                OneView(selectedTab: $selectedTab, calculated: $calculated)
                    .tabItem {
                        Label("One", systemImage: "1.circle")
                    }
                    .tag(TabChoice.one)
                TwoView(selectedTab: $selectedTab, calculated: $calculated)
                    .tabItem {
                        Label("Two", systemImage: "2.circle")
                    }
                    .tag(TabChoice.two)
            }
        }
    }
}
}

OneView

import SwiftUI

struct OneView: View {

@Binding var selectedTab: TabChoice
@Binding var calculated: CalculatedChoice

var body: some View {
    VStack {
        Spacer()
        Text("TabView 1")
        Spacer()
        HStack{
            NavigationLink(destination: TwoView(selectedTab: $selectedTab, calculated: $calculated).navigationBarBackButtonHidden(true))   {
                Text("Press to Load TabView2 Programatically")
            }
        }
        Spacer()
    }
}
}

TwoView

import SwiftUI

struct TwoView: View {

@Binding var selectedTab: TabChoice
@Binding var calculated: CalculatedChoice

var body: some View {
    VStack {
        Spacer()
        Text("TabView 2")
        Spacer()
    }
    
}
}

Many thanks to lorem ipsum for politely pushing me to create an MRE so the issues are clearer to see. Screen shots below:

enter image description here

enter image description here

enter image description here

enter image description here

Edward Hasted
  • 3,201
  • 8
  • 30
  • 48
  • Why not using buttons in place of navigation links ? Also pay attention that modifying selectedTab in any view will modify it in all created views and so redraw these. – Ptit Xav Aug 17 '23 at 17:55
  • Like I mentioned in the other post a TabView cannot be inside a NavigationStack (or 2 for that matter) per HIG. This is the source of many bugs and now crashes. Each tab must be independent from the rest of the tabs, they can’t share a hierarchy. – lorem ipsum Aug 17 '23 at 19:55
  • But if I bring the NavigationStack() inside the TabView() in MenuView I get the two screens showing on the same page. You mention this issue a lot. Are there any examples I can follow? All the ones I have come across are simplistic and don't need the NavigationStack. – Edward Hasted Aug 18 '23 at 07:58

2 Answers2

0

You can update your code like that for OneView:

struct OneView: View {
    
    @Binding var selectedTab: TabChoice
    @Binding var calculated: CalculatedChoice
    
    var body: some View {
        VStack {
            Spacer()
            Text("TabView 1")
            Spacer()
            HStack{
                Text("Press to Load TabView2 Programatically").onTapGesture {
                    selectedTab = .two
                }
            }
            Spacer()
        }
    }
}
EsatGozcu
  • 185
  • 8
  • That introduces two TabView button 1s? .onTapGesture is a useful tool. – Edward Hasted Aug 18 '23 at 07:49
  • Question is not clear please give me more detail. – EsatGozcu Aug 18 '23 at 08:37
  • The @State var/@Binding deal with stuff in the View. I think my issue is that I want be able to make the MenuView() show a specific screen, One or Two. Because when you press a tab that is handled in the View it works. I want to be able to specify which View you see when you press a button. – Edward Hasted Aug 19 '23 at 09:30
0

I have ended up using:

 Button(action: {selectedTab = TabChoice.one}, label: { Text("Press to Load TabView2 Programatically") })

This seems too simple and I am sure I tried this previously. I will delete this question shortly, unless anyone finds any merit in it. I thinks it's been a red herring and I am very grateful for everyone's help and patience.

Edward Hasted
  • 3,201
  • 8
  • 30
  • 48