Interface Builder中的WKWebView


95

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



4
我正在使用Xcode 7.2,但在对象库中看不到WKWebView。它仍然不可用吗?
user3731622'1

10
仍然不存在在Xcode 8.
瑞恩巴兰坦

1
Xcode 9.0.1现在在IB中支持WKWebView。现在已弃用这里的所有答案。
smileBot

1
@smileBot新版本的Xcode确实具有WKWebView,但它要求您将iOS 11+作为目标。crx_au答案效果最好-> stackoverflow.com/a/40118654/757503
mikemike396

Answers:


70

您是正确的-似乎没有用。如果您查看标题,将会看到:

- (instancetype)initWithCoder:(NSCoder *)coder NS_UNAVAILABLE;

这意味着您无法从笔尖实例化一个。

您必须在viewDidLoad或loadView中手动完成此操作。


希望他们会在某个时候改变它,但是我认为这没什么大不了的。Johan指出了WWDC视频,甚至它们都在代码中实例化。
亚当·福克斯

3
从有利的一面,在代码这样做会让你的iOS 8使用的UIWebView中的iOS 7和WKWebView
埃里克斯

好了,在此答案之后,我想您可以在WKWebView的子类中重写此方法,然后在接口生成器中使用它。.但是没有super.initWithCoder ..让我们测试吧!:)
zarghol 2015年

1
经过个人测试:您不能...“无法覆盖已标记为不可用的'init'”太糟糕了
zarghol 2015年

2
要做的一件合理的事情可能是创建一个名为MyWebView的UIView子视图,该子视图具有WKWebView或UIWebView作为子视图,并在运行时在initWithCoder中确定。然后,您可以在IB中创建MyWebView视图。如果您使用的是Swift,甚至可以使用IBInspectable关键字添加可以在IB中编辑的属性。
EricS 2015年

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)
        }
    }
}

13
这个问题专门关于Interface Builder,因此这个答案不是很有帮助。
史蒂夫·兰迪2014年

5
你是对的。我应该以“您无法从IB创建WKWebView”开始回答:),但是我观看了来自WWDC的会话视频“ Introducing Modern WebKit API”,他们正在使用Xcode,所以我想这仅仅是不对的。目前尚不可用。
2014年

1
只需再次签出视频,他们就会在代码中实例化其WKWebView。大约是视频中的17:20。
亚当·福克斯

3
如何创建无限循环?这是来自iOS文档中loadView的描述。“当请求其视图属性但当前为nil时,视图控制器将调用此方法。”
约翰,

2
引用 self.view内部loadView()是导致无限递归的原因。另一方面,设置视图不仅是允许的,而且确实是必需的(手动或通过链接到super。否则,只要视图为,它将一直被调用nil)。
Nicolas Miari '16

29

信息清单

添加您的Info.plist传输安全设置

 <key>NSAppTransportSecurity</key>
 <dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
 </dict>

Xcode 9.1以上

使用界面构建器

您可以在对象库中找到WKWebView元素。

在此处输入图片说明

使用Swift 5以编程方式添加视图

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

使用Swift 5以编程方式添加视图(完整示例)

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)
    }
}

在的初始值设定项中分配新视图不是一个好建议WebView。crx_au的反应非常出色
Ilias Karim

我没有发现其他有效的方法!所以...就像ILI4S所说的那样,这可能不是一个好建议,我不知道它是否正确,但可以正常工作!谢谢,您救了我的一天!:)
豪尔赫·科尔德罗

20

借助Xcode 8,现在可以实现这一点,但是至少可以说,实现它的方法有些棘手。但是,嘿,一个可行的解决方案就是一个可行的解决方案,对吗?让我解释。

WKWebView的initWithCoder:不再注释为“ NS_UNAVAILABLE”。现在看起来如下图所示。

- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;

首先子类化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;
}

在情节提要中,使用UIView并为其提供新子类的自定义类。其余一切照常进行(设置自动布局约束,将视图链接到控制器中的插座等)。

最后,WKWebView缩放内容的方式与UIWebView不同。许多人可能希望遵循Suppress WKWebView中的简单建议,即缩放内容以与UIWebView相同的放大率进行渲染,以使WKWebView在这方面更紧密地遵循UIWebView行为。


2
self = [super initWithFrame:myFrame configuration:myConfiguration];如果您使用约束,它也应该阅读,别忘了设置self.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66

除了使用主屏幕的边界作为占位符框架之外,您还可以使用CGRectZero并保存一些代码。
伊利亚斯·卡里姆

不错的解决方案。效果很好。
Rayfleck '17

完美无瑕!不错的修复方法,因为无需定向iOS 11即可在情节提要中获取WKWebView约束。
mikemike396 '18

20

这是一个基于crx_au的出色答案的简单Swift 3版本。

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
    }
}

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

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


出色的答案
Amr Hossam'9

6

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

#import <WebKit/WebKit.h>
  1. 修复之前: 在此处输入图片说明

  2. 修复后:

在此处输入图片说明


4

现在,这显然已在Xcode 9b4中修复。发行说明说:“ WKWebView在iOS对象库中可用。”

我还没有进一步了解它是否需要iOS 11或向后兼容。


我可以确认这有效!万岁!它也适用于macOS故事板(至少适用于针对macOS 10.13+的应用程序)。
克利夫顿拉布鲁姆

1

从Xcode 9开始,您可以在IB中实例化和配置WKWebView,而无需在代码中进行操作。 在此处输入图片说明

请注意,尽管您的部署目标必须高于iOS 10,否则您将获得编译时错误。

在此处输入图片说明




0

不确定这是否有帮助,但是我通过为目标包括WebKit框架为我解决了问题。不嵌入它只是链接参考。我仍然在IB中使用WebView对象,并将其放到我要嵌入的ViewController中,我从来没有遇到过问题...

我现在已经处理了4个WKWebView MacOS项目,并且WebView在每个项目中都能正常工作。


-14

这在Xcode 7.2中对我有用...

首先在情节提要/ IB中将Web视图添加为UIWebView出口。这将为您提供如下属性:

@property (weak, nonatomic) IBOutlet UIWebView *webView;

然后,只需编辑代码即可将其更改为WKWebView。

@property (weak, nonatomic) IBOutlet WKWebView *webView;

您还应该在身份检查器中将自定义类更改为WKWebView。


我在OS X项目中尝试了此操作-该项目无法正常工作,因此对于iOS来说必须是特殊情况。
henrikstroem 2015年

2
您所做的就像打字一样。它根本无法更改webView的类型。
DawnSong
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.