4

Views in SwiftUI have a transparent background by default. This usually means that they have a white background because that's the default background color of your app. However, this also means that you can use a ZStack to change the background color of your entire app and that color will show through all your views unless you explicitly set their own background color:

struct Main: View {
    var body: some View {
        ZStack {
            Color.orange.edgesIgnoringSafeArea(.all)

            // Sub-view inlined
            VStack {
                Text("Hello World")
                Button("Press Me", action: { print("Pressed") })
            }
        }
    }
}

enter image description here

The problem I have run into is that this is not true for a TabView:

struct Main: View {
    var body: some View {
        ZStack {
            Color.orange.edgesIgnoringSafeArea(.all)

            // Sub-view inlined
            TabView {
                VStack {
                    Text("Hello World")
                    Button("Press Me", action: { print("Pressed") })
                }.tabItem {
                    Text("First Page")
                }
            }
        } 
    }
}

The TabView blocks the background color:

enter image description here

I can change the background color of the subview, but if I make it transparent, the background is white again instead of showing the underlying color in the ZStack. I've also tried sundry other ways to make the TabView transparent, such as setting its background to Color.clear, but to no avail.

TL;DR

Is it possible to make a TabView transparent instead of white?

Caleb Kleveter
  • 11,170
  • 8
  • 62
  • 92

1 Answers1

5

The hosting view of every tab has system background color (which is opaque).

demo1

Here is possible workaround. Tested with Xcode 12 / iOS 14

demo

struct BackgroundHelper: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        DispatchQueue.main.async {
            // find first superview with color and make it transparent
            var parent = view.superview
            repeat {
                if parent?.backgroundColor != nil {
                    parent?.backgroundColor = UIColor.clear
                    break
                }
                parent = parent?.superview
            } while (parent != nil)
        }
        return view
    }

    func updateUIView(_ uiView: UIView, context: Context) {}
}

struct ContentView: View {
    var body: some View {
        ZStack {
            Color.orange.edgesIgnoringSafeArea(.all)

            // Sub-view inlined
            TabView {
                VStack {
                    Text("Hello World")
                    Button("Press Me", action: { print("Pressed") })
                }
                .background(BackgroundHelper())  // add to each tab if needed
                .tabItem {
                    Text("First Page")
                }
                Text("Second")
                    .background(BackgroundHelper())  // add to each tab if needed
                    .tabItem {
                        Text("Second Page")
                    }
            }
        }
    }
}
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • This worked when the first tab item was selected, but even with the background helper added to all items, the rest did not get a transparent background. – Caleb Kleveter Aug 04 '20 at 16:33
  • Every tab has own background, so yes, it should be added, if needed, to every tab. What do you mean by *the rest*? – Asperi Aug 04 '20 at 17:11
  • I added the custom background to all the tab item views. The view for the first tab item has a transparent background, but the views for the rest of the tab items (I have 4 total) do not have a transparent background, despite me adding the modifier to them. – Caleb Kleveter Aug 04 '20 at 17:17
  • Just retested - works fine. Make sure you added modifier *before* `.tabItem` as updated. – Asperi Aug 04 '20 at 17:23
  • This is weird. I'm using the `.tag` modifier so I can connect each tab item to an enum case. When I remove this modifier, it starts working. – Caleb Kleveter Aug 04 '20 at 17:30
  • Never mind. I think I'm just going crazy. It's working now. Must have messed something up before without realizing it. Thanks for the help. – Caleb Kleveter Aug 04 '20 at 17:33
  • The view flashes when first switched tab because the modifier needs the dispatch which skips a frame (but removing the dispatch causes it to have no effect) - any solution to that? Thanks! – hyouuu Nov 27 '21 at 22:58