15

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()?

Rob Smallshire
  • 1,450
  • 1
  • 15
  • 22

2 Answers2

3

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)

Pradeep K
  • 3,671
  • 1
  • 11
  • 15
  • If you can convince me that you've actually tried this n a Mac, and that it works, I'll accept this answer. I'm away from my Mac for the next few days, so can't verify it myself. – Rob Smallshire Feb 25 '16 at 18:48
  • Yes, I did this on a Mac and answered. Here's a video of the app. http://www.filedropper.com/untitled480p – Pradeep K Feb 26 '16 at 03:55
  • Dear lord, I've spent the last hour tearing my hair out trying to figure out why my window with my web view wouldn't render, and this was the answer. I wish I could give you a million upvotes :) – davertron Mar 22 '22 at 23:02
1

So my first reaction was: why don't you just add the WKWebView into the storyboard? That way, you can size it so that it will be the size of the enclosing window. Turns out you cannot add a WKWebView into Interface Builder (which is why I think you had to go this route).

loadView, by default, connects an instantiated view from a nib to the view property of the view controller. The problem with overriding loadView and then assigning self.view is that it breaks the storyboard relationship that the window content has with your ViewController.

So the solution is to wait for self.view to be loaded from the storyboard and then add WKWebView as a subview:

- (void)viewDidLoad {
    WKWebView *wb = [[WKWebView alloc] initWithFrame:self.view.frame];
    [wb loadHTMLString:@"<html><body><p>Hello, World!</p></body></html>" baseURL:nil];
    [self.view addSubview:wb];
}

I only have the Objective-C. Sorry haven't learned Swift yet.

rocky
  • 3,521
  • 1
  • 23
  • 31
  • The problem with this method is that it doesn't resize when the window is resized. What the original question is trying to do is to change the view of the ViewController itself to a web view. – Pradeep K Feb 25 '16 at 03:58
  • The original question asks how to make "a WKWebView fill its containing window using the window dimensions and positions specified in the storyboard" which is exactly what my code does. There is no mention of resizing. – rocky Feb 25 '16 at 04:43
  • Resizing is indeed required. The window in the storyboard is resizable, so the WKWebView should resize with it, as Pradeep says. – Rob Smallshire Feb 25 '16 at 18:45
  • Like I said, nothing in the question requires that. If you need it to resize, edit your question. – rocky Feb 25 '16 at 18:47
  • @rocky What about the sentence "The WKWebView should resize with the enclosing window."? – Rob Smallshire Feb 27 '16 at 21:02
  • For resizing with window, add `wb.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;` – dchest Mar 25 '22 at 23:17