WKWebView in Interface Builder


95

Sembra che i modelli di oggetti IB in XCode 6 beta stiano ancora creando oggetti vecchio stile (UIWebView per iOS e WebView per OSX). Si spera che Apple li aggiorni per il moderno WebKit, ma fino ad allora, qual è il modo migliore per creare WKWebViews in Interface Builder? Devo creare una visualizzazione di base (UIView o NSView) e assegnarne il tipo a WKWebView? La maggior parte degli esempi che trovo online lo aggiungono a una visualizzazione contenitore a livello di programmazione; è meglio per qualche motivo?



4
Sto usando Xcode 7.2, non vedo WKWebView nella libreria degli oggetti. Non è ancora disponibile?
user3731622

10
Ancora non presente in Xcode 8.
Ryan Ballantyne

1
Xcode 9.0.1 ora supporta WKWebView in IB. Tutte le risposte qui sono ora deprecate.
smileBot

1
@smileBot La nuova versione di Xcode ha WKWebView ma richiede di scegliere come target iOS 11+. risposta crx_au funziona meglio -> stackoverflow.com/a/40118654/757503
mikemike396

Risposte:


70

Hai ragione: non sembra funzionare. Se guardi nelle intestazioni, vedrai:

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

il che implica che non è possibile istanziarne uno da un pennino.

Dovrai farlo a mano in viewDidLoad o loadView.


Si spera che prima o poi lo cambieranno, ma suppongo non sia un grosso problema. Johan mi ha rimandato al video WWDC, e anche loro stanno istanziando in codice.
Adam Fox

3
Tra i lati positivi, farlo nel codice ti consentirà di utilizzare UIWebView in iOS 7 e WKWebView in iOS 8.
EricS

Bene, dopo questa risposta, penso che tu possa sovrascrivere questo metodo in una sottoclasse di WKWebView e quindi usarlo nel generatore di interfacce .. ma senza super.initWithCoder .. testiamo! :)
zarghol

1
Dopo un test personale: non puoi ... "Impossibile sovrascrivere 'init' che è stato contrassegnato come non disponibile"
peccato

2
Una cosa ragionevole da fare potrebbe essere quella di creare una sottoview UIView denominata MyWebView che ha WKWebView o UIWebView come sottoview, determinata in fase di esecuzione in initWithCoder. Quindi puoi creare visualizzazioni MyWebView in IB. Se utilizzi Swift, puoi persino aggiungere proprietà che possono essere modificate in IB utilizzando la parola chiave IBInspectable.
EricS

65

Come sottolineato da alcuni, a partire da Xcode 6.4, WKWebView non è ancora disponibile su Interface Builder. Tuttavia, è molto facile aggiungerli tramite codice.

Lo sto solo usando nel mio ViewController. Saltare il generatore di interfacce

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
Questa domanda riguarda specificamente Interface Builder, quindi questa risposta non è molto utile.
Steve Landey

5
Hai ragione. Avrei dovuto iniziare la risposta con "Non puoi creare WKWebView da IB" :) Ma guardo il video della sessione "Presentazione dell'API Modern WebKit" da WWDC e stanno usando Xcode quindi immagino che questo sia solo qualcosa che non è ' t disponibile per noi al momento.
Johan

1
Ho appena controllato di nuovo il video e stanno creando un'istanza del loro WKWebView nel codice. È intorno alle 17:20 nel video.
Adam Fox

3
Come creerà un loop infinito? Questo è tratto dalla descrizione di loadView nella documentazione di iOS. "Il controller di visualizzazione chiama questo metodo quando viene richiesta la sua proprietà di visualizzazione, ma attualmente è nulla."
Johan,

2
Fare riferimento self.view all'internoloadView()è ciò che porta alla ricorsione infinita. L'impostazione della vista, d'altra parte, non solo è consentita ma addirittura richiesta (manualmente o concatenandola asuper. Altrimenti continuerà a essere chiamata fintanto che la vista ènil).
Nicolas Miari

29

Info.plist

aggiungi nelle impostazioni di sicurezza del trasporto di Info.plist

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

Xcode 9.1+

Utilizzo del generatore di interfacce

Puoi trovare l'elemento WKWebView nella libreria degli oggetti.

inserisci qui la descrizione dell'immagine

Aggiungi la vista a livello di codice con 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

Aggiungi la vista a livello di codice con Swift 5 (esempio completo)

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

Non è un buon suggerimento per allocare una nuova vista nell'inizializzatore per WebView. La risposta di crx_au è superiore
Ilias Karim

Non ho trovato nessun'altra cosa che funzioni !! Quindi ... come ha detto ILI4S forse non è un buon suggerimento, non so se lo sia o no, ma funziona correttamente! Grazie amico, mi hai salvato la giornata !! :)
Jorge Cordero

20

Con Xcode 8 ora è possibile, ma i mezzi per ottenerlo sono a dir poco un po 'complicati. Ma hey, una soluzione funzionante è una soluzione funzionante, giusto? Lasciatemi spiegare.

InitWithCoder di WKWebView: non è più annotato come "NS_UNAVAILABLE". Ora appare come mostrato di seguito.

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

Inizia creando una sottoclasse WKWebView e sovrascrivi initWithCoder. Invece di chiamare super initWithCoder, dovrai usare un metodo init diverso, come initWithFrame: configuration :. Un rapido esempio di seguito.

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

Nel tuo Storyboard, usa una UIView e assegnagli una classe personalizzata della tua nuova sottoclasse. Il resto è come al solito (impostazione dei vincoli di layout automatico, collegamento della vista a una presa in un controller, ecc.).

Infine, WKWebView ridimensiona il contenuto in modo diverso rispetto a UIWebView. Molte persone probabilmente vorranno seguire il semplice consiglio in Impedisci a WKWebView di ridimensionare il contenuto per renderlo con lo stesso ingrandimento di UIWebView per fare in modo che WKWebView segua più da vicino il comportamento di UIWebView a questo proposito.


2
dovrebbe leggere self = [super initWithFrame:myFrame configuration:myConfiguration];anche se si utilizzano vincoli, non dimenticare di impostareself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66

Piuttosto che usare i limiti della schermata principale come una cornice segnaposto, puoi anche usare CGRectZero e salvarti un po 'di codice.
Ilias Karim

Bella soluzione. Funziona bene.
Rayfleck

Funziona perfettamente! Bella soluzione per non dover scegliere come target iOS 11 per ottenere i vincoli di WKWebView nello storyboard.
mikemike396

20

Ecco una semplice versione di Swift 3 basata sull'eccellente risposta di 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
    }
}

Crea una UIView in Interface Builder, assegna i tuoi vincoli e assegnala WKWebView_IBWrappercome classe personalizzata, in questo modo:

Utilità -> scheda Identity Inspector [1]


Ottima risposta
Amr Hossam,

6

Se continui a riscontrare questo problema nelle versioni recenti di Xcode, ovvero v9.2 +, importa semplicemente Webkit nel tuo ViewController:

#import <WebKit/WebKit.h>
  1. Prima della correzione: inserisci qui la descrizione dell'immagine

  2. Dopo la correzione:

inserisci qui la descrizione dell'immagine


4

Questo è ora apparentemente risolto in Xcode 9b4. Le note sulla versione dicono "WKWebView è disponibile nella libreria di oggetti iOS".

Non ho esaminato più a fondo per vedere se richiede iOS 11 o è ancora compatibile con le versioni precedenti.


Posso confermare che funziona! Evviva! Funziona anche negli storyboard di macOS (almeno per le app destinate a macOS 10.13+).
Clifton Labrum

1

È possibile creare un'istanza e configurare un WKWebView in IB da Xcode 9, non è necessario farlo nel codice. inserisci qui la descrizione dell'immagine

Tieni presente che il tuo obiettivo di distribuzione deve essere superiore a iOS 10, altrimenti riceverai un errore in fase di compilazione.

inserisci qui la descrizione dell'immagine


0

In XCode versione 9.0.1 WKWebView è disponibile su Interface Builder.



0

Non sono sicuro che questo aiuti, ma ho risolto il problema includendo il framework WebKit per l'obiettivo. Non incorporarlo, basta collegare il riferimento. Uso ancora l'oggetto WebView in IB e lo rilascio sul ViewController in cui lo sto incorporando e non ho mai avuto problemi ...

Ho lavorato su 4 progetti WKWebView per MacOS ora e WebView ha funzionato correttamente in ogni progetto.


-14

Questo ha funzionato per me in Xcode 7.2 ...

Per prima cosa aggiungi la visualizzazione Web come presa UIWebView nello storyboard / IB. Questo ti darà una proprietà come questa:

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

Quindi modifica il tuo codice per cambiarlo in un WKWebView.

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

Dovresti anche cambiare la classe personalizzata in WKWebView nell'Identity Inspector.


L'ho provato con un progetto OS X - non funziona, quindi deve essere un caso speciale per iOS.
henrikstroem

2
Quello che fai è proprio come il cast di caratteri. NON può cambiare affatto il tipo di webView.
DawnSong
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.