Home > Software design >  WKWebView not resizing in fullscreen when added in SwiftUI with NSScrollView
WKWebView not resizing in fullscreen when added in SwiftUI with NSScrollView

Time:06-10

Adding a custom NSScrollView into SwiftUI, there is a WKWebview inside a HStack which is added to NSScrollView via NSHostingView

The WKWebview doesn't go fullscreen properly (doesnt resize and sticks to the leading edge) when child.translatesAutoresizingMaskIntoConstraints = false, if I skip this then the fullscreen works as normal however the AutoLayout won't work because of this.

     struct ContentView: View {
      var body: some View {
        VStack {
            ScrollViewX {
                HStack {
   
                    WebViewX()
                    .frame(width: 300, height: 300)
           
                }
            }
            .frame(width: 500, height : 500)
            
        }.frame(width: 700, height : 700)
    }
    }



    struct ScrollViewX<Content : View>: NSViewRepresentable {
    let content: Content

    init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }

    func makeNSView(context: Context) -> CustomScrollView {
        let view = CustomScrollView(frame: .zero)
        let child = NSHostingView(rootView: content)
        child.translatesAutoresizingMaskIntoConstraints = false
        view.documentView = child
       child.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
       child.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        return view
    }

    func updateNSView(_ nsView: CustomScrollView, context: Context) {
    }
     }

     class CustomScrollView: NSScrollView {
    
     override init(frame frameRect: NSRect) {
        super.init(frame: frameRect)
        self.drawsBackground = false
        self.hasHorizontalScroller = true
        self.hasVerticalScroller = false
        
        self.translatesAutoresizingMaskIntoConstraints = false
    }
        
        required init?(coder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }

    }

     struct WebViewX: NSViewRepresentable {

    
    func makeNSView(context: Context) -> customWebView {
        let webView = customWebView(url: nil)
        return webView
    }
        
    func updateNSView(_ NSView: customWebView, context: Context) {
    }
     }

    class customWebView : WKWebView {
    convenience init(url : String?) {
        

        let config = WKWebViewConfiguration()
        
        config.limitsNavigationsToAppBoundDomains = false
        config.preferences.isTextInteractionEnabled = true
        config.preferences.setValue(true, forKey: "fullScreenEnabled")
        config.preferences.javaScriptCanOpenWindowsAutomatically = true
        config.defaultWebpagePreferences.allowsContentJavaScript = true
        self.init(frame: .zero, configuration : config)

        self.allowsBackForwardNavigationGestures = false
        self.allowsMagnification = true
        
        self.translatesAutoresizingMaskIntoConstraints = false

        let req = URLRequest(url: URL(string: "https://www.youtube.com")!)
        
        self.load(req)

    }
    
    convenience required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
     }

CodePudding user response:

Solved it thanks to @Asperi

The issue is due to the frame() on WebViewX()

When you add a NSHostingView() in Appkit the SwiftUI frame modifier disables the view from resizing during fullscreen.

The solution is to change the frame() on willEnterFullscreen and exitFullscreen notifications.

Maybe there are better solutions using Auto-layout

CodePudding user response:

All conditions still not clear, but actually it is horizontal scroller, so height definitely can be constraint, but for content... every view have to have some width defined (or at least have some rule to calculate). Any other hardcodes should be removed.

Thus with below changes all works in full screen as expected automatically (tested with Xcode 13.4 / macOS 12.4)

demo

// in main: 

        VStack {
            ScrollViewX {
                HStack {
                    WebViewX(url: "https://www.apple.com")
                        .frame(width: 500)
                    WebViewX(url: "https://www.google.com")
                        .frame(width: 500)
                    WebViewX(url: "https://www.stackoverflow.com")
                        .frame(width: 500)
                    WebViewX()
                        .frame(width: 500)
                }
            }
        }
    }

// in ScrollViewX:

    func makeNSView(context: Context) -> CustomScrollView {
        let view = CustomScrollView(frame: .zero)
        let child = NSHostingView(rootView: content)
        child.translatesAutoresizingMaskIntoConstraints = false
        view.documentView = child
        child.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
        child.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        // this one !!
        child.heightAnchor.constraint(equalTo: view.heightAnchor).isActive = true
        return view
    }

Complete test code is here

  • Related