I have a basic NSViewRepresentable
implementation of WKWebView
, for use with SwiftUI apps on macOS. The UIViewRepresentable
equivalent works fine on iOS, but on macOS (natively, not Catalyst), the top content is always cut off.
The amount lost always equals the size of parent views (such as the tab view) and their padding, which indicates that the web view keeps scaling its content to the window size, rather than the view size.
For example, this page:
...should be as follows (as shown in Chrome). The entire navigation bar has been cropped out (though the sides appear not to be affected).
Any suggestions on how to fix this? Interestingly, if I switch back & forth between tabs, the content shows correctly for ~1 second, then resizes the content so it's cut off again. This makes me think something's required in the updateNSView
method, but I'm not sure what.
Seems to be a similar issue to the one discussed here, but that's for IB-based apps, and I can't see a way to apply it for SwiftUI.
The code used is as follows. Note: The web view is kept as a property so it can be referenced by other methods (such as triggering page load, refresh, go back, etc.)
public struct WebBrowserView {
private let webView: WKWebView = WKWebView()
// ...
public func load(url: URL) {
webView.load(URLRequest(url: url))
}
public class Coordinator: NSObject, WKNavigationDelegate, WKUIDelegate {
var parent: WebBrowserView
init(parent: WebBrowserView) {
self.parent = parent
}
public func webView(_: WKWebView, didFail: WKNavigation!, withError: Error) {
// ...
}
public func webView(_: WKWebView, didFailProvisionalNavigation: WKNavigation!, withError: Error) {
// ...
}
public func webView(_: WKWebView, didFinish: WKNavigation!) {
// ...
}
public func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
// ...
}
public func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
decisionHandler(.allow)
}
public func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
if navigationAction.targetFrame == nil {
webView.load(navigationAction.request)
}
return nil
}
}
public func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
}
#if os(macOS) // macOS Implementation (iOS version omitted for brevity)
extension WebBrowserView: NSViewRepresentable {
public typealias NSViewType = WKWebView
public func makeNSView(context: NSViewRepresentableContext<WebBrowserView>) -> WKWebView {
webView.navigationDelegate = context.coordinator
webView.uiDelegate = context.coordinator
return webView
}
public func updateNSView(_ nsView: WKWebView, context: NSViewRepresentableContext<WebBrowserView>) {
}
}
#endif
Example usage:
struct BrowserView: View {
private let browser = WebBrowserView()
var body: some View {
HStack {
browser
.onAppear() {
self.browser.load(url: URL(string: "https://stackoverflow.com/tags")!)
}
}
.padding()
}
}
struct ContentView: View {
@State private var selection = 0
var body: some View {
TabView(selection: $selection){
Text("Email View")
.tabItem {
Text("Email")
}
.tag(0)
BrowserView()
.tabItem {
Text("Browser")
}
.tag(1)
}
.padding()
}
}
webView.edgesIgnoringSafeArea(.all)
seems to work around this problem.
The solution by @Ahmed with GeometryReader
is quite elegant, yet I've found a shorter workaround.
struct BrowserView: View {
// ...
var body: some View {
// ...
browser.padding(-1.0)
// ...
}
}
Seems that the default padding, which equals to 0, causes this issue. So I just set it to -1.
I had the exact same issue with WKWebView in MacOS app using SwiftUI.
The solution that worked for me is to use GeometryReader to get the exact height, and put the web view inside a scrollview (I believe it has something to do with the layout priority calculation, but couldn't get to the core of it yet).
Here is a snippet of what worked for me, maybe it will work with you as well
GeometryReader { g in
ScrollView {
BrowserView().tabItem {
Text("Browser")
}
.frame(height: g.size.height)
.tag(1)
}.frame(height: g.size.height)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With