WKWebView в интерфейсе строителя


похоже, что шаблоны объектов IB в бета-версии XCode 6 все еще создают объекты старого стиля (UIWebView для iOS и WebView для OSX). Надеюсь, Apple обновит их для современного WebKit, но до тех пор, каков лучший способ создать WKWebViews в Interface Builder? Должен ли я создать базовое представление (UIView или NSView) и назначить его тип WKWebView? Большинство примеров, которые я нахожу в интернете, добавляют его в представление контейнера программно; это лучше по какой-то причине?

10 87

10 ответов:

вы правы - это, кажется, не работает. Если вы посмотрите в заголовках, вы увидите:

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

что означает, что вы не можете создать экземпляр из пера.

вы должны будете сделать это вручную в viewDidLoad или loadView.

как указывали некоторые, начиная с 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)
        }
    }
}

Xcode 9.1

вы можете найти элемент WKWebView в библиотеке объектов.

enter image description here

Swift 3 и Xcode 8

используя раскадровку

ViewController.Свифт

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

Главная.раскадровка

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

С Xcode 8 это теперь возможно, но средства достижения этого немного хаки, чтобы не сказать больше. Но эй, рабочее решение-это рабочее решение, верно? Позвольте мне объяснить.

initWithCoder WKWebView: больше не аннотируется как "NS_UNAVAILABLE". Теперь он выглядит так, как показано ниже.

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

начать WKWebView, разделяя на подклассы и переопределить initWithCoder. Вместо вызова super initWithCoder вам нужно будет использовать другой метод init, например initWithFrame:конфигурации:. Быстрый пример ниже.

- (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. Многие люди, вероятно, захотят следовать простым советам в подавить WKWebView от масштабирования содержимого для визуализации в то же время увеличение как UIWebView делает чтобы сделать WKWebView более внимательно следить за поведением UIWebView в этом отношении.

вот простая версия 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
    }
}

создайте UIView в Interface Builder, назначьте свои ограничения и назначьте его WKWebView_IBWrapper как пользовательский класс, например:

Utilities -> Identity Inspector Tab[1]

теперь это, по-видимому, исправлено в Xcode 9b4. В примечаниях к выпуску говорится: "WKWebView доступен в библиотеке объектов iOS."

Я не заглядывал глубже, чтобы увидеть, требует ли он iOS 11 или обратно совместим.

вы можете создать экземпляр и настроить WKWebView в IB с Xcode 9, не нужно делать это в коде. enter image description here

обратите внимание, что ваша цель развертывания должна быть выше, чем iOS 10, Хотя или вы получите ошибку времени компиляции.

enter image description here

в XCode версии 9.0.1 WKWebView доступен на Interface Builder.

Если вы все еще сталкиваетесь с этой проблемой в последних версиях Xcode, т. е. v9. 2+, просто импортируйте Webkit в ViewController:

#import <WebKit/WebKit.h>
  1. до исправления: enter image description here

  2. после исправления:

enter image description here

это работает для меня в Xcode 7.2...

Сначала добавьте веб-представление в качестве выхода UIWebView в раскадровке / IB. Это даст вам свойство, как это:

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

затем просто изменить свой код, чтобы изменить его на WKWebView.

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

вы также должны изменить пользовательский класс на WKWebView в инспекторе идентификации.