Interface Builder中的WKWebView

问题描述 投票:90回答:11

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

ios xcode macos uiwebview wkwebview
11个回答
69
投票

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

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

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

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


0
投票

我已经链接了WebKit,现在它正在运行!

example


-12
投票

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

首先将Web视图添加为storyboard / IB中的UIWebView插座。这会给你一个这样的属性:

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

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

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

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


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

27
投票

的Info.plist

添加Info.plist传输安全设置

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

对于Xcode 9.1,Xcode 10.2

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

enter image description here

适用于Swift 3和Xcode 8

使用StoryBoard

ViewController.swift

import UIKit
import WebKit

// Add WKWebView in StoryBoard
class ViewController: UIViewController {

    @IBOutlet var webView: WebView!

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        webView.loadUrl(string: "http://apple.com")
    }
}

class WebView: WKWebView {

    required init?(coder: NSCoder) {

        if let _view = UIView(coder: coder) {
            super.init(frame: _view.frame, configuration: WKWebViewConfiguration())
            autoresizingMask = _view.autoresizingMask
        } else {
            return nil
        }
    }

    func loadUrl(string: String) {
        if let url = URL(string: string) {
            load(URLRequest(url: url))
        }
    }
}

Main.storyboard

<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11542" systemVersion="16B2555" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <deployment identifier="iOS"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11524"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--View Controller-->
        <scene sceneID="tne-QT-ifu">
            <objects>
                <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_24167812" customModuleProvider="target" sceneMemberID="viewController">
                    <layoutGuides>
                        <viewControllerLayoutGuide type="top" id="y3c-jy-aDJ"/>
                        <viewControllerLayoutGuide type="bottom" id="wfy-db-euE"/>
                    </layoutGuides>
                    <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0zg-ri-o6Y" customClass="WebView" customModule="stackoverflow_24167812" customModuleProvider="target">
                                <rect key="frame" x="0.0" y="20" width="375" height="647"/>
                                <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                                <color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
                            </view>
                        </subviews>
                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                    </view>
                    <connections>
                        <outlet property="webView" destination="0zg-ri-o6Y" id="G0g-bh-eej"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="140" y="138.98050974512745"/>
        </scene>
    </scenes>
</document>

编程

import UIKit
import WebKit

// Add WKWebView programmatically
class ViewController: UIViewController {

    var webView: WKWebView?

    override func viewDidLoad() {
        super.viewDidLoad()
        // init webView
        webView = WKWebView(frame: view.bounds)
        view.addSubview(webView!)
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        // load url
        webView?.loadUrl(string: "http://apple.com")
    }
}

extension WKWebView {
    func loadUrl(string: String) {
        if let url = URL(string: string) {
            load(URLRequest(url: url))
        }
    }
}

18
投票

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

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

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

最后,WKWebView以不同的方式缩放内容到UIWebView。许多人可能会想要遵循Suppress WKWebView from scaling content to render at same magnification as UIWebView does中的简单建议,使WKWebView更加密切地遵循这方面的UIWebView行为。


16
投票

这是一个简单的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
    }
}

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


4
投票

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

我没有深入了解它是否需要iOS 11或者是向后兼容的。


2
投票

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

#import <WebKit/WebKit.h>
  1. 在修复之前:enter image description here
  2. 修复后:

enter image description here


1
投票

您可以在Xcode 9中实例化和配置IB中的WKWebView,无需在代码中执行此操作。 enter image description here

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

enter image description here


0
投票

在XCode版本9.0.1中,Interface Builder上提供了WKWebView。

© www.soinside.com 2019 - 2024. All rights reserved.