Caleb Kleveter
Caleb Kleveter

Reputation: 11484

Make TabView Background Transparent

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?

Upvotes: 8

Views: 2773

Answers (1)

Asperi
Asperi

Reputation: 257493

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")
                    }
            }
        }
    }
}

Upvotes: 9

Related Questions