Search code examples
swiftuiios13ios-navigationview

Changing background of NavigationView's bar when presented modally


I can't figure out a way to set the navigation bar to be opaque black...

All the related hacks don't seem to work if the navigation view is presented modally...

This is how I present my webView:

               Button(action: { self.showFAQ.toggle() }) {
                        Text("Frequently Asked Questions").foregroundColor(.orange)
                    }.sheet(isPresented: $showFAQ) {
                        WebView(isPresented: self.$showFAQ, url: self.faqURL)
                    }

This is my webView wrapper:

struct WebView: View {
    let url: URL

    @Binding var isPresented: Bool

    var body: some View {
        NavigationView {
            WebViewRepresentable(url: url)
                .navigationBarTitle("", displayMode: .inline)
                .navigationBarItems(trailing: Button(action: {
                    self.isPresented.toggle()
                }, label: { Text("Done") } ))
        }
    }

    init(isPresented: Binding<Bool>, url: URL) {
        self.url = url
        self._isPresented = isPresented

        let appearance = UINavigationBarAppearance()
        appearance.configureWithOpaqueBackground()
    }

    struct WebViewRepresentable: UIViewRepresentable {
        let url: URL

        // Creates a UIKit view to be presented.
        func makeUIView(context: Context) -> WKWebView {
            let webView = WKWebView()
            webView.isOpaque = false
            webView.backgroundColor = .systemBackground
            return webView
        }

        // Updates the presented UIKit view (and its coordinator)
        // to the latest configuration.
        func updateUIView(_ uiView: WKWebView, context: Context) {
            let req = URLRequest(url: url)
            uiView.load(req)
        }
    }
}

UINavigationBarAppearance() is ignored... UINavigationBar.appearance() is also ignored...


Solution

  • A possible solution is to avoid using a NavigationView and simply add a Done button to achieve the same result:

    struct WebView: View {
        let url: URL
    
        @Binding var isPresented: Bool
    
        var body: some View {
            VStack {
                HStack {
                    Spacer()
                    Button(action: {
                        self.isPresented.toggle()
                    }) {
                        Text("Done").padding(.all, 20)
                    }
                }
                WebViewRepresentable(url: url)
            }.background(Color.black.opacity(1.0))
             .edgesIgnoringSafeArea(.all)
        }
    
        init(isPresented: Binding<Bool>, url: URL) {
            self.url = url
            self._isPresented = isPresented
    
            let appearance = UINavigationBarAppearance()
            appearance.configureWithOpaqueBackground()
        }
    
        struct WebViewRepresentable: UIViewRepresentable {
            let url: URL
    
            // Creates a UIKit view to be presented.
            func makeUIView(context: Context) -> WKWebView {
                let webView = WKWebView()
                webView.isOpaque = false
                webView.backgroundColor = .systemBackground
                return webView
            }
    
            // Updates the presented UIKit view (and its coordinator)
            // to the latest configuration.
            func updateUIView(_ uiView: WKWebView, context: Context) {
                let req = URLRequest(url: url)
                uiView.load(req)
            }
        }
    }