Interface Builder中的WKWebView

Ada*_*Fox 94 macos xcode uiwebview ios wkwebview

似乎XCode 6 beta中的IB对象模板仍然在创建旧式对象(iOS的UIWebView和OSX的WebView).希望Apple能够为现代WebKit更新它们,但在此之前,在Interface Builder中创建WKWebViews的最佳方法是什么?我应该创建一个基本视图(UIView或NSView)并将其类型分配给WKWebView吗?我在网上找到的大多数例子都是以编程方式将它添加到容器视图中; 是出于某种原因更好吗?

Eri*_*icS 69

你是对的 - 它似乎不起作用.如果您查看标题,您会看到:

- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;
Run Code Online (Sandbox Code Playgroud)

这意味着你无法从笔尖中实例化一个.

你必须在viewDidLoad或loadView中手动完成.

  • 从好的方面来说,在代码中执行它将允许您使用iOS 7中的UIWebView和iOS 8中的WKWebView. (3认同)
  • 一个合理的做法可能是创建一个名为MyWebView的UIView子视图,该子视图具有WKWebView或UIWebView作为子视图,在运行时在initWithCoder中确定.然后,您可以在IB中创建MyWebView视图.如果您使用的是Swift,您甚至可以使用IBInspectable关键字添加可在IB中编辑的属性. (2认同)
  • @IBInspectable也适用于Objective-C.:) (2认同)

Joh*_*han 65

正如一些人所指出的,从Xcode 6.4开始,WKWebView在Interface Builder上仍然不可用.但是,通过代码添加它们非常容易.

我只是在我的ViewController中使用它.跳过界面生成器

import UIKit
import WebKit

class ViewController: UIViewController {

    private var webView: WKWebView?

    override func loadView() {
        webView = WKWebView()

        //If you want to implement the delegate
        //webView?.navigationDelegate = self

        view = webView
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        if let url = URL(string: "https://google.com") {
            let req = URLRequest(url: url)
            webView?.load(req)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这个问题是关于Interface Builder的,所以这个答案不是很有用. (13认同)
  • 你是对的.我应该用"你不能从IB创建WKWebView"开始回答:)但是我从WWDC观看会话视频"Introducing the Modern WebKit API",他们正在使用Xcode,所以我想这只是一个不是'我们此刻可以使用. (5认同)
  • 它将如何创建无限循环?这是来自iOS文档中的loadView的描述."视图控制器在请求view属性但当前为nil时调用此方法." (3认同)
  • **_在`loadView()`中引用_**`self.view`是导致无限递归的原因.**_另一方面,设置_**视图不仅是允许的,而且确实**需要**(手动或链接到`super`.否则只要视图为'nil'它就会被调用). (2认同)

Vas*_*huk 28

Xcode 9.1

您可以在Object库中找到WKWebView元素.

在此输入图像描述

Swift 3和Xcode 8

使用StoryBoard

ViewController.swift

 <key>NSAppTransportSecurity</key>
 <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
 </dict>
Run Code Online (Sandbox Code Playgroud)

Main.storyboard

let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
view.addSubview(webView)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
webView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
webView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
Run Code Online (Sandbox Code Playgroud)

编程

import UIKit
import WebKit

class ViewController: UIViewController {

    private weak var webView: WKWebView!

    override func viewDidLoad() {
        super.viewDidLoad()
        initWebView()
        webView.loadPage(address: "http://apple.com")
    }

    private func initWebView() {
        let webView = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
        view.addSubview(webView)
        self.webView = webView
        webView.translatesAutoresizingMaskIntoConstraints = false
        webView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
        webView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor).isActive = true
        webView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
        webView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor).isActive = true
    }
}

extension WKWebView {
    func loadPage(address url: URL) { load(URLRequest(url: url)) }
    func loadPage(address urlString: String) {
        guard let url = URL(string: urlString) else { return }
        loadPage(address: url)
    }
}
Run Code Online (Sandbox Code Playgroud)


小智 19

使用Xcode 8现在可以实现这一点,但实现它的方法至少可以说是有点hacky.但是,嘿,工作解决方案是一个有效的解决方案,对吗?让我解释.

WKWebView的initWithCoder:不再注释为"NS_UNAVAILABLE".它现在看起来如下所示.

- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
Run Code Online (Sandbox Code Playgroud)

从子类化WKWebView开始并覆盖initWithCoder.您不需要调用超级initWithCoder,而是需要使用不同的init方法,例如initWithFrame:configuration:.下面的简单示例.

- (instancetype)initWithCoder:(NSCoder *)coder
{
    // An initial frame for initialization must be set, but it will be overridden 
    // below by the autolayout constraints set in interface builder. 
    CGRect frame = [[UIScreen mainScreen] bounds];
    WKWebViewConfiguration *myConfiguration = [WKWebViewConfiguration new];

    // Set any configuration parameters here, e.g.
    // myConfiguration.dataDetectorTypes = WKDataDetectorTypeAll; 

    self = [super initWithFrame:frame configuration:myConfiguration];

    // Apply constraints from interface builder.
    self.translatesAutoresizingMaskIntoConstraints = NO;

    return self;
}
Run Code Online (Sandbox Code Playgroud)

在您的Storyboard中,使用UIView并为其提供新子类的自定义类.其余部分照常营业(设置自动布局约束,将视图链接到控制器中的插座等).

最后,WKWebView以不同的方式缩放内容到UIWebView.很多人可能会想要遵循Suppress WKWebView中的简单建议,从缩放内容到以与UIWebView相同的放大率渲染,以使WKWebView更密切地遵循这方面的UIWebView行为.

  • 它应该是`self = [super initWithFrame:myFrame configuration:myConfiguration];`如果你使用约束,也不要忘记设置`self.translatesAutoresizingMaskIntoConstraints = NO;` (2认同)

Gam*_*mma 18

这是一个简单的Swift 3版本,基于crx_au的优秀答案.

import WebKit

class WKWebView_IBWrapper: WKWebView {
    required convenience init?(coder: NSCoder) {
        let config = WKWebViewConfiguration()
        //config.suppressesIncrementalRendering = true //any custom config you want to add
        self.init(frame: .zero, configuration: config)
        self.translatesAutoresizingMaskIntoConstraints = false
    }
}
Run Code Online (Sandbox Code Playgroud)

在Interface Builder中创建UIView,分配约束,并将其指定WKWebView_IBWrapper为自定义类,如下所示:

实用程序 - > Identity Inspector选项卡[1]


MrD*_*DEV 6

如果您在最新版本的 Xcode(即 v9.2+)中仍然遇到此问题,只需将 Webkit 导入您的 ViewController:

#import <WebKit/WebKit.h>
Run Code Online (Sandbox Code Playgroud)
  1. 修复前: 在此处输入图片说明

  2. 修复后:

在此处输入图片说明