WKWebView doesn't show from the begin in NSViewRepresentable

I face an issue when I put

WKWebView
to
View
. As you can see Web page doesn't show from the begin.


When I change the app window size the page shows correctly.



What could be the problem?


import SwiftUI
import WebKit

struct WebView: NSViewRepresentable {
  func makeNSView(context: Context) -> WKWebView {
  let view = WKWebView()
  guard let url = URL(string: "https://github.com/filimo/ReaderTranslator") else { return view }
  view.load(URLRequest(url: url))
  return view
  }

  func updateNSView(_ view: WKWebView, context: Context) {

  }
}

struct WKWebViewDemo: View {
  var body: some View {
  WebView()
  }
}


I left the link with images on https://stackoverflow.com/q/58491837/4067700


If I added Text with multiple lines then WebView is trunced of the top.


var body: some View {
        VStack {
            Text("line\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\nline\n")
            WebView()
        }
    }

Replies

The problem is that WKWebView can't do anything until the view is properly loaded and initialized. You might want to move the "load..." call into a Dispatch.async... call. That way it'll be called after the web view has been returned (and hopefully has been initialized).


Here is a quick playground example.

import SwiftUI
import WebKit
import PlaygroundSupport

struct WebView: UIViewRepresentable {
    func makeUIView(context: UIViewRepresentableContext<WebView>) -> WKWebView {
        let view = WKWebView()
        DispatchQueue.main.async {
            let url = URL(string:"https://example.com")!
            let request = URLRequest(url: url)
            view.load(request)
        }
        return view
    }

    func updateUIView(_ uiView: WKWebView, context: UIViewRepresentableContext<WebView>) {
        //
    }

    typealias UIViewType = WKWebView
  }  


struct ContentView : View {
    var body: some View {
        WebView()
    }
}


// Present the view controller in the Live View window
PlaygroundPage.current.liveView = UIHostingController(rootView: ContentView())

Moving the load() call into updateNSView() appears to do the trick, though since that method is called on every single event (including mouse-over events), you need to be able to exit quickly after the first time you load the URL.


Here's my implementation:


import SwiftUI
import WebKit

struct WebView: NSViewRepresentable {
    let url: URL

    func makeNSView(context: Context) -> WKWebView {
        let view = WKWebView()
        view.autoresizingMask = [.width, .height]
        return view
    }

    func updateNSView(_ nsView: WKWebView, context: Context) {
        guard context.coordinator.needsToLoadURL else { return }
        nsView.load(URLRequest(url: url))
    }

    func makeCoordinator() -> WebView.Coordinator {
        Coordinator()
    }

    class Coordinator {
        var needsToLoadURL = true
    }
}

struct WebKitView_Previews: PreviewProvider {
    static var previews: some View {
        WebView(url: URL(string: "...")!)
    }
}