3

I have a pretty usual app with a TabView. However, when a particular process is happening in one of the content views, I would like to prevent the user from switching tabs until that process is complete.

If I use the disabled property on the TabView itself (using a @State binding to drive it), then the entire content view seems disabled - taps don't appear to be getting through to buttons on the main view.

Example:

struct FooView: View {
    var body: some View {
        TabView {
            View1().tabItem(...)
            View2().tabItem(...)
        }
        .disabled(someStateVal)
    }
}

Obviously, I want the View1 to still allow the user to, you know, do things. When someStateVal is true, the entire View1 doesn't respond.

Is there a way to prevent changing tabs based on someStateVal?

Thanks!

Hoopes
  • 3,943
  • 4
  • 44
  • 60

2 Answers2

3

I could not find a way to individually disable a tabItem, so here is an example idea until someone comes up with more principled solution.

The trick is to cover the tab bar with a clear rectangle to capture the taps.

struct ContentView: View {
    @State var isBusy = false
    
    var body: some View {
        ZStack {
            TabView {
                TestView(isBusy: $isBusy)
                    .tabItem {Image(systemName: "globe")}
                Text("textview 2")
                    .tabItem {Image(systemName: "info.circle")}
                Text("textview 3")
                    .tabItem {Image(systemName: "gearshape")}
            }
            VStack {
                Spacer()
                if isBusy {
                    Rectangle()
                        .fill(Color.white.opacity(0.001))
                        .frame(width: .infinity, height: 50)
                }
            }
        }
    }
}

struct TestView: View {
    @Binding var isBusy: Bool
    
    var body: some View {
        VStack {
            Text("TestView")
            Button(action: {
                isBusy.toggle()
            }) {
                Text("Busy \(String(isBusy))").frame(width: 170, height: 70)
            }
        }
    }
}
0

I use another trick. Just hide the tab image.

struct FooView: View {
    var body: some View {
        TabView {
            View1().tabItem{Image(systemName: someStateVal ? "": "globe")}
            View2().tabItem{Image(systemName: someStateVal ? "": "gearshape")}
        }
    }
}
claude31
  • 874
  • 6
  • 8