Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

like image 964
Rob Smallshire Avatar asked Feb 15 '16 20:02

Rob Smallshire


People also ask

How do I import WKWebView into Objective C?

You can implement WKWebView in Objective-C, here is simple example to initiate a WKWebView : WKWebViewConfiguration *theConfiguration = [[WKWebViewConfiguration alloc] init]; WKWebView *webView = [[WKWebView alloc] initWithFrame:self. view. frame configuration:theConfiguration]; webView.

How do I add WKWebView to my storyboard?

First add the web view as a UIWebView outlet in the storyboard / IB. This will give you a property like this: @property (weak, nonatomic) IBOutlet UIWebView *webView; Then just edit your code to change it to a WKWebView.

Is WKWebView same as Safari?

WKWebView - This view allows developers to embed web content in your app. You can think of WKWebView as a stripped-down version of Safari. It is responsible to load a URL request and display the web content. WKWebView has the benefit of the Nitro JavaScript engine and offers more features.

What is WKWebView in Swift?

A WKWebView object is a platform-native view that you use to incorporate web content seamlessly into your app's UI. A web view supports a full web-browsing experience, and presents HTML, CSS, and JavaScript content alongside your app's native views.


2 Answers

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)

like image 149
Pradeep K Avatar answered Oct 16 '22 23:10

Pradeep K


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.

like image 1
rocky Avatar answered Oct 16 '22 22:10

rocky