Tulon
Tulon

Reputation: 4136

Is it possible to make the "Presentation Hosting Controller" background color transparent instead of white color in SwiftUI?

I am trying to make a "FullScreenModalView" where you can send any view with a fixed height and width and it will show with a modal presentation. It is working perfectly but I can't make the "Presentation Hosting Controller" background color transparent. I tried a couple of solutions like setting a custom transparent view as a background view, but still it has no effect on the "Presentation Hosting Controller" background color.

What I want to achieve:
enter image description here

But in the view hierarchy I can see the background color of the Presentation Hosting Controller is white, which I need to set as a clear color.
enter image description here

My code:
ContentView

import SwiftUI

struct ContentView: View {
    @State private var isShowingCommonMenu = false
    @State private var isPresented = false
    
    var body: some View {
        VStack {
            Button {
                //MARK: Show Network Configure List
                self.isShowingCommonMenu.toggle()
            } label: {
                Text("GO")
            }
            .fullScreenCover(isPresented: $isShowingCommonMenu) {
                NavigationStack {
                    GeometryReader { geometry in
                        FullScreenModalView(isShowingCommonMenu: $isShowingCommonMenu, childViewWidth: (geometry.size.width - geometry.size.width/10), childViewHeight: geometry.size.height) {
                            TheViewToBeLoadedView()
                        }
                    }
                }
            }
        }
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        .background(Color.orange)
        .padding()
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

FullScreenModalView

import SwiftUI

struct FullScreenModalView<Content: View>: View {
    @Binding var isShowingCommonMenu: Bool
    var childViewWidth: CGFloat
    var childViewHeight: CGFloat
    let content: () -> Content
    
    var body: some View {
        ZStack {
            Color.black.opacity(0.4)
                .edgesIgnoringSafeArea(.all)
                .onTapGesture {
                    //Dismiss the modal view when the user taps outside of it
                    dismiss()
                }
            
            VStack {
                content()
                    .background(ClearBackgroundView())
            }
            .frame(width: childViewWidth, height: childViewHeight)
            .background(Color.white)
            .cornerRadius(10)
            .overlay(
                Button {
                    dismiss()
                } label: {
                    DismissButton()
                }, alignment: .topTrailing)
        }
        .ignoresSafeArea(.keyboard)
        .background(TransparentBackground())
    }
    
    private func dismiss() {
        isShowingCommonMenu = false
    }
}

struct FullScreenModalView_Previews: PreviewProvider {
    static var previews: some View {
        FullScreenModalView(isShowingCommonMenu: .constant(true), childViewWidth: 200, childViewHeight: 200) {
            Text("This is a custom preview view")
        }
    }
}
struct TransparentBackground: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        DispatchQueue.main.async {
            view.superview?.superview?.backgroundColor = .clear
        }
        return view
    }

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

struct DismissButton: View {
    var body: some View {
        ZStack {
            Circle()
                .frame(width: 30, height: 30)
                .foregroundColor(.white)
                .opacity(0.6)
            Image(systemName: "xmark")
                .imageScale(.medium)
                .frame(width: 44, height: 44)
                .foregroundColor(Color(.label))
        }
    }
}

And the sample view that I want to load:

import SwiftUI

struct TheViewToBeLoadedView: View {
    var body: some View {
        GeometryReader { geometry in
            Text("TheViewToBeLoadedView")
                .frame(width: geometry.size.width, height: geometry.size.height, alignment: .center)
                .background(Color.yellow)
        }
    }
}

struct TheViewToBeLoadedView_Previews: PreviewProvider {
    static var previews: some View {
        TheViewToBeLoadedView()
    }
}

Upvotes: 7

Views: 1324

Answers (1)

LearnLoop
LearnLoop

Reputation: 112

Apply .background(TransparentBackground()) on the Content in .fullScreenCover

e.g.

struct ContentView: View {
    @State private var showingFullscreenModal: Bool = false

    var body: some View {
        VStack {
            Button {
                showingFullscreenModal.toggle()
            } label: {
                Text("Show Fullscreen Modal")
            }
        }
        .frame(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height)
        .background(.orange)

        .fullScreenCover(isPresented: $showingFullscreenModal) {
            SubView(showing: $showingFullscreenModal, width: 300, height: 400)
                .background(TransparentBackground()) // <--- Here
        }
    }
}

struct TransparentBackground: UIViewRepresentable {
    func makeUIView(context: Context) -> UIView {
        let view = UIView()
        DispatchQueue.main.async {
            view.superview?.superview?.backgroundColor = .clear
        }
        return view
    }

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


struct SubView: View {
    @Binding var showing: Bool
    
    let width: CGFloat
    let height: CGFloat
    
    var body: some View {
        VStack {
            Text("Hello World")
            
            Button {
                showing = false
            } label: {
                Text("Close")
            }
        }
        .frame(width: width, height: height)
        .background(.teal)
    }
}

enter image description here

So, in your case, apply .background(TransparentBackground()) on NavigationStack in .fullScreenCover

Upvotes: 8

Related Questions