0

I have created a TabBar which is a view at the root of the app. I'd like to hide the TabBar component when navigating from the closet view to a subview. The Closet view is a NavigationView containing multiple NavigationLink

Here is the root view of the app:

struct Home: View {
@State var selected = 0
@ObservedObject var viewModel: HomeViewModel

init(viewModel: HomeViewModel) {
    self.viewModel = viewModel
}

var body: some View {
    ZStack {
        
        if self.selected == 0 {
            // viewModel.feedView
            Stylist()
        }
        else if self.selected == 1 {
            OutfitView()
        }
        else if self.selected == 2 {
            viewModel.closetView
        } else {
            Calendar()
        }
        
        VStack {
            Spacer()
            TabBar(selected: self.$selected)
                .frame(width: UIScreen.main.bounds.width - 20, alignment: .center)
        }
    }
}

Here is the TabBar component:

var body : some View{
    HStack{
        Spacer(minLength: 0)
        
        HStack{
            Button(action: {
                
                self.selected = 0
                
            }) {
                
                Image(systemName: "bolt.fill").foregroundColor(self.selected == 0 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
            }
            
            Spacer(minLength: 15)
            
            Button(action: {
                
                self.selected = 1
                
            }) {
                
                Image(systemName: "sun.min.fill").foregroundColor(self.selected == 1 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
            }
            
            Spacer(minLength: 15)
            
            Button(action: {
                
                self.selected = 2
                
            }) {
                
                Image(systemName: "cube.box.fill").foregroundColor(self.selected == 2 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
            }
            
            Spacer(minLength: 15)
            
            Button(action: {
                
                self.selected = 4
                
            }) {
                
                Image(systemName: "calendar").foregroundColor(self.selected == 4 ? Color("GradientMiddle") : .gray).padding(.horizontal).font(.system(size: 20))
            }
        }.padding(.vertical, 20)
            .padding(.horizontal)
            .background(Color(UIColor.systemGray5))
            .clipShape(Capsule())
            .padding(42)
            .animation(.interactiveSpring(response: 0.6, dampingFraction: 0.6, blendDuration: 0.6))
    }
    
    
}

Is there an way to that properly ?

Update: When I try @Asperi solution I have an error:

Value of type 'some View' has no member 'observingNavigate'

Maybe that could be caused by how I create closetView ? So here is how I create ClosetView: HomeViewModel.swift:

class HomeViewModel: ObservableObject {
} 
extension HomeViewModel { 
    var closetView: some View { 
        return HomeBuilder.makeClosetView() 
    }
}

HomeBuilder.swift:

enum HomeBuilder {
    static func makeClosetView() -> some View { 
        let viewModel = ClosetViewModel()
        return Closet(viewModel: viewModel) 
    } 
}
jscatigna
  • 21
  • 2
  • Did you tried this https://stackoverflow.com/questions/57304876/how-to-hide-the-tabbar-when-navigate-with-navigationlink-in-swiftui ? – gcharita Aug 22 '20 at 11:57

1 Answers1

0

You need a callback from your Closet view so root view can perform some action. Here is a demo of possible solution.

Let's assume we have the following demo ClosetView

struct ClosetView: View {
    var didNavigate: ((Bool) -> Void)?

    var body: some View {
        NavigationView {
            NavigationLink("Link", destination:
                Text("Demo")
                    .onAppear { didNavigate?(true) }
                    .onDisappear { didNavigate?(false) }
            )
        }
    }

    func observingNavigate(callback: @escaping ((Bool) -> Void)) -> some View {
        var view = self
        view.didNavigate = callback
        return view
    }
}

then changes in Home will be the following

@State private var showTabbar = true    // << state !!

var body: some View {
    ZStack {
        
        if self.selected == 0 {
            // viewModel.feedView
            Stylist()
        }
        else if self.selected == 1 {
            OutfitView()
        }
        else if self.selected == 2 {
            viewModel.closetView
              .observingNavigate { self.showTabbar = !$0 }   // << here !!
        } else {
            Calendar()
        }
        
        VStack {
            Spacer()
            if showTabbar {                      // << here !!
              TabBar(selected: self.$selected)
                .frame(width: UIScreen.main.bounds.width - 20, alignment: .center)
            }
        }
    }
}

Note: I don't see how you create viewModel.closetView so callback is injected as property, however it can also be injected via constructor arguments, but this does not change idea much.

Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I have a Value of type 'some View' has no member 'observingNavigate' Maybe that could be caused by how I create closetView ? – jscatigna Aug 23 '20 at 08:59
  • here is how it is done: class HomeViewModel: ObservableObject { } extension HomeViewModel { var closetView: some View { return HomeBuilder.makeClosetView() } } – jscatigna Aug 23 '20 at 08:59
  • enum HomeBuilder { static func makeClosetView() -> some View { let viewModel = ClosetViewModel() return Closet(viewModel: viewModel) } } – jscatigna Aug 23 '20 at 09:00