Creating View inside TabView without showing its icon on tab bar

The main View of the App is TabView with 2 screens.

I need to create an Onboarding View (there are a lot of those) and they are in their own NavigationStack. The Onboarding View shows only at the first launch.

It would be great for design requirements if i could put Onboarding View like item of TabView, with "0" tag, but without icon displaying on tapbar.

I mean, when opens my TabView, there should be no OnboardingView in it(which is .tag(0)). But i can set logic of app to open on .tag(0) on first launch, and .tag(1) on every next.

Of course, i would hide tapBar on OnboardingView.

TabView(selection: $vm.tabSelection,
        content: {
    OnboardingView()
        .tag(0)
    FirstView()
        .tabItem {
            Image(systemName: "sparkles")
            Text("SecondView")
        }
        .tag(1)
    SecondView()
        .navigationTitle("SecondView")
        .tabItem {
            Text("Remove BG")
            Image(systemName: "eraser.line.dashed")
        }
        .tag(2)
}
...

Upvotes: 0

Views: 155

Answers (1)

Benzy Neez
Benzy Neez

Reputation: 21700

As I was suggesting in a comment, you could switch between the onboarding view and the TabView by using a ZStack as the top-level parent view.

You said that this wouldn't work because you are using popovers and popover tips in FirstView. The standalone example below demonstrates that in fact it can work.

The only issue I came across was that the popover tip was not shown with the right width when using a .move transition between onboarding and TabView. But when a (default) opacity transition is used, it works fine.

struct ContentView: View {
    @State private var onboardingDone = false
    @State private var tabSelection = 1

    var body: some View {
        ZStack {
            if onboardingDone {
                TabView(selection: $tabSelection) {
                    FirstView(onboardingDone: $onboardingDone)
                        .tabItem {
                            Image(systemName: "sparkles")
                            Text("SecondView")
                        }
                        .tag(1)
                    SecondView()
                        .tabItem {
                            Text("Remove BG")
                            Image(systemName: "eraser.line.dashed")
                        }
                        .tag(2)
                }
            } else {
                OnboardingView(onboardingDone: $onboardingDone)
            }
        }
    }
}

struct OnboardingView: View {
    @Binding var onboardingDone: Bool
    var body: some View {
        NavigationStack {
            NavigationLink("Go to next") {
                VStack(spacing: 50) {
                    Text("Onboarding completed")
                    Button("Ready for FirstView") {
                        withAnimation {
                            onboardingDone = true
                        }
                    }
                    .buttonStyle(.bordered)
                }
            }
            .navigationTitle("OnboardingView")
        }
    }
}

struct FirstView: View {
    @Binding var onboardingDone: Bool

    struct QuickTip: Tip {
        var title: Text {
            Text("Want to onboard again?")
        }

        var message: Text? {
            Text("The button to reset the onboarding is in the next view")
        }

        var image: Image? {
            Image(systemName: "hand.thumbsup.circle")
        }
    }

    var body: some View {
        NavigationStack {
            NavigationLink("Go to next") {
                VStack(spacing: 50) {
                    Text("Child of FirstView")
                    Button("Reset onboarding") {
                        withAnimation {
                            onboardingDone = false
                        }
                    }
                    .buttonStyle(.bordered)
                }
            }
            .popoverTip(QuickTip())
            .onAppear {
                try? Tips.resetDatastore()
                try? Tips.configure()
            }
            .navigationTitle("FirstView")
        }
    }
}

struct SecondView: View {
    @State private var isShowingPopover = false

    var body: some View {
        NavigationStack {
            NavigationLink("Go to next") {
                VStack(spacing: 50) {
                    Text("Child of SecondView with Popover")
                        .onTapGesture {
                            isShowingPopover.toggle()
                        }
                        .popover(isPresented: $isShowingPopover, arrowEdge: .bottom) {
                            Text("Interesting popover")
                                .padding()
                                .presentationCompactAdaptation(.popover)
                        }
                }
            }
            .navigationTitle("SecondView")
        }
    }
}

Animation

Upvotes: 0

Related Questions