-1

My app has 3 tabs (Read, Discover, Profile). In one specific view that is navigated to from the the Read view, I want to hide the tab view and show a custom toolbar/tab bar that will show action buttons (e.g, save, like).

I have been Googling and searching Stack Overflow for 2 days and no luck. This is what I've seen / tried:

  • Hide tab view: Seems like this is simply not possible with SwiftUI. There are a few hacks posted on this site but they don't work for me (e.g., try use UITabBarController modifications) or too compromised (e.g., wrap tab view in navigation view which results in tab view disappearing in all sub views)
  • Use root page: This works, but then navigation view breaks (can't get back button back)
  • Conditional tab view: I didn't see this posted anywhere, but gave it a go. I tried an if statement in the tab view with a bool state variable, where the main tabs (Read, Discover, Profile) are set to default, and on the specific sub view page, a different tab view is used (e.g, with Save buttons). But that also doesn't seem to work.

Anyone have ideas or examples of working code? Thanks!

deanseg
  • 21
  • 2
  • please read and consider https://stackoverflow.com/help/how-to-ask and https://stackoverflow.com/help/minimal-reproducible-example – Chris May 25 '20 at 02:12
  • Thanks, although some specific feedback would be appreciated on how the question could be improved as this is my first time posting. If it is because I didn’t include code, the guidance is pretty clear that code is not a requirement. Or is it? – deanseg May 25 '20 at 03:08
  • Consider a solution provied in [SwiftUI Hide TabView bar inside NavigationLink views](https://stackoverflow.com/a/61971653/12299030) – Asperi May 25 '20 at 03:25
  • Thanks! That’s clear - I’ll add reproducible code shortly. – deanseg May 25 '20 at 03:26

2 Answers2

1

I have implemented two solutions in the code below:

  1. Update tabs on the go
  2. Go to a specific view on tab
enum MyTab: String {
    case a, b, c, d

    var view: AnyView {
        switch self {
        case .a, .b: return AnyView(ChildView(page: rawValue))
        case .c, .d: return AnyView(SpecificView())
        }
    }
}

class ViewModel: ObservableObject {

    @Published var tabs: [MyTab] = [.a, .b]
    @Published var selectedTab: MyTab = .a
    @Published var shouldShowTab = true

    var customBinding: Binding<MyTab> {
        Binding(get: {
            self.selectedTab
        }, set: {
            if $0 == .c {
                // save
            } else if $0 == .d {
                // like
            }
            self.selectedTab = $0
        })
    }

    func updateTabs() {
        tabs = [.c, .d]
    }
}

struct ContentView: View {

    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        Group {
            if viewModel.shouldShowTab {
                TabView(selection: viewModel.customBinding) {
                    ForEach(viewModel.tabs, id: \.self) { tab in
                        tab.view
                            .tabItem { Text(tab.rawValue) }
                    }
                }
            } else {
                SpecificView()
            }
        }
    }
}

struct ChildView: View {

    @EnvironmentObject var viewModel: ViewModel
    var page: String

    var body: some View {
        VStack(spacing: 24) {
            Text("Page: \(page)")
            Button(action: {
                self.viewModel.shouldShowTab = false
            }) {
                Text("Go to Specific View")
            }
            Button(action: {
                self.viewModel.updateTabs()
            }) {
                Text("or update tabs on the go")
            }
        }
    }
}

struct SpecificView: View {

    @EnvironmentObject var viewModel: ViewModel

    var body: some View {
        // Use whatever you'd like tab etc.
        VStack(spacing: 24) {
            Text("My Specific View")
            Button(action: {
                self.viewModel.shouldShowTab = true
            }) {
                Text("Go back to Tab View")
            }
        }
    }
}
Cuneyt
  • 931
  • 5
  • 11
  • Brilliant thank you! This works so well and gives flexibility to either hide or update tabs. Thanks! – deanseg May 25 '20 at 13:03
0

You can show your new view as a Sheet, that way the specific view you mentioned can have its own TabView.

struct ContentView: View {

    @State var presentView = false

    var body: some View {
        Button(action: {
            self.presentView.toggle()
        }) {
            Text("Present View")
        }
        .sheet(isPresented: $presentView) {
            TabView {
                // content
            }
        }
    }
}
Cuneyt
  • 931
  • 5
  • 11
  • Thanks! That’s definitely an option if there is no other way. I expect users to spend quite a bit of time in the view and so the modal approach unfortunately doesn’t feel right in that context - feels more of a quick pop up. – deanseg May 25 '20 at 03:15
  • No problem! Can you please explain the UX you want to achieve with more details? I have also gave a new answer, please have a look. – Cuneyt May 25 '20 at 03:49