Search code examples
swiftmacoscocoawkwebviewnsviewcontroller

How to configure a WKWebView to fill an NSWindow?


I have a small prototype application developed in Swift with XCode 7.2. The application was created as a Cocoa document-based application with a storyboard. As such, the project contains AppDelegate.swift, Document.swift and Main.storyboard, all of which are unchanged from what XCode generated, and ViewController.swift, which contains this:

import Cocoa
import WebKit

class ViewController: NSViewController {

    var webView: WKWebView {
        return view as! WKWebView
    }

    override func loadView() {
        view = WKWebView(/*frame: CGRect(x: 0, y: 0, width: 200, height: 200)*/)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        // Do any additional setup after loading the view.
        webView.loadHTMLString("<html><body><p>Hello, World!</p></body></html>", baseURL: nil)
    }
}

I have overridden loadView() to directly create the a WKWebView and assign it to the view property of ViewController as the root view, rather than loading the view defined in the storyboard.

Notice that the frame argument to WKWebView may be commented in or out to demonstrate the different behaviours which are at the root of this question.

Desired behaviour

A WKWebView instance should fill the window corresponding to each document, and the initial size and position of new document windows should be those defined for the NSWindow in the storyboard (480x270 at (196, 240)). The WKWebView should resize with the enclosing window.

Observed behaviour

Without the frame argument

Without the frame argument, no document window is displayed when running the application, even though the Window menu shows that an 'Untitled' document has been created. Neither are document windows displayed when further documents (Untitled 2, etc) are created with File > New.

However, if a document is shown full-screen using the View > Enter Full Screen, the WKWebView and its greeting are displayed as expected.

With the frame argument

With the frame argument, document windows containing the WKWebView and its greeting are displayed at the size and position given in the CGRect.

Question

I don't understand why, when the frame of the WKWebView is not specified, the view is forced to the size of the container (the screen) in full-screen mode, but in windowed mode the opposite seemingly happens: The window is forced to the (degenerate?) size of the view, and so becomes invisible. I was expecting new views to adopt the size of the window as defined in the storyboard.

In my ViewController, how do I configure my WKWebView instances to fill the NSWindow the document framework produces corresponding to each NSDocument? Or, perhaps my approach is wrong-headed, and I should embrace configuring the initial window size via the view size in ViewController.loadView()?


Solution

  • Try this method. You should call the super.loadView() first. This will give you the initial size of the view that is loaded from the storyboard. Then you change the view itself to the web view using the frame of the original view. Hope this solves your problem.

    override func loadView() {
        super.loadView()
        view = WKWebView(frame:self.view.frame)
    }
    

    You can also try setting the background color of the web view to see that its working.

    webView.loadHTMLString("<html><body bgcolor=red><p>Hello, World!</p></body></html>", baseURL: nil)