WKWebView di Interface Builder

95

Tampaknya template objek IB di XCode 6 beta masih membuat objek gaya lama (UIWebView untuk iOS dan WebView untuk OSX). Mudah-mudahan Apple akan memperbaruinya untuk WebKit modern, tetapi sampai saat itu, apa cara terbaik untuk membuat WKWebView di Interface Builder? Haruskah saya membuat tampilan dasar (UIView atau NSView) dan menetapkan tipenya ke WKWebView? Sebagian besar contoh yang saya temukan online menambahkannya ke tampilan penampung secara terprogram; apakah itu lebih baik untuk beberapa alasan?

Adam Fox
sumber
4
Saya menggunakan Xcode 7.2, saya tidak melihat WKWebView di perpustakaan objek. Apakah masih belum tersedia?
pengguna3731622
10
Masih tidak ada di Xcode 8.
Ryan Ballantyne
1
Xcode 9.0.1 sekarang mendukung WKWebView di IB. Semua jawaban di sini sekarang tidak digunakan lagi.
smileBot
1
@smileBot Versi baru Xcode memang memiliki WKWebView tetapi mengharuskan Anda untuk menargetkan iOS 11+. jawaban crx_au berfungsi paling baik -> stackoverflow.com/a/40118654/757503
mikemike396

Jawaban:

70

Anda benar - sepertinya tidak berhasil. Jika Anda melihat di header, Anda akan melihat:

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

yang menyiratkan bahwa Anda tidak dapat membuat instance dari ujung pena.

Anda harus melakukannya dengan tangan di viewDidLoad atau loadView.

EricS
sumber
Mudah-mudahan mereka akan mengubahnya di beberapa titik, tapi saya rasa itu bukan masalah besar. Johan mengarahkan saya kembali ke video WWDC, dan bahkan mereka membuat contoh dalam kode.
Adam Fox
3
Sisi positifnya, melakukannya dalam kode akan memungkinkan Anda menggunakan UIWebView di iOS 7 dan WKWebView di iOS 8.
EricS
Nah setelah jawaban ini, saya rasa Anda dapat mengganti metode ini dalam subkelas WKWebView dan kemudian menggunakannya di pembuat antarmuka .. tetapi tanpa super.initWithCoder .. mari kita uji! :)
zarghol
1
Setelah tes pribadi: Anda tidak dapat ... "Tidak dapat menimpa 'init' yang telah ditandai tidak tersedia" terlalu buruk ...
zarghol
2
Satu hal yang masuk akal untuk dilakukan adalah membuat subview UIView yang disebut MyWebView yang memiliki WKWebView atau UIWebView sebagai subview, ditentukan saat runtime di initWithCoder. Kemudian Anda dapat membuat tampilan MyWebView di IB. Jika Anda menggunakan Swift, Anda bahkan dapat menambahkan properti yang dapat diedit di IB menggunakan kata kunci IBInspectable.
EricS
65

Seperti yang ditunjukkan oleh beberapa orang, pada Xcode 6.4, WKWebView masih belum tersedia di Interface Builder. Namun, sangat mudah untuk menambahkannya melalui kode.

Saya hanya menggunakan ini di ViewController saya. Melewati pembuat Antarmuka

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)
        }
    }
}
Johan
sumber
13
Pertanyaan ini secara khusus tentang Pembuat Antarmuka, jadi jawaban ini tidak terlalu membantu.
Steve Landey
5
Kamu benar. Saya seharusnya memulai jawaban dengan “Anda tidak dapat membuat WKWebView dari IB" :) Tapi saya menonton video sesi “Memperkenalkan API WebKit Modern" dari WWDC dan mereka menggunakan Xcode jadi saya rasa ini hanyalah sesuatu yang isn ' tidak tersedia untuk kami saat ini.
Johan
1
Baru saja memeriksa videonya lagi, dan mereka membuat instance WKWebView dalam kode. Ada sekitar tanda 17:20 di video.
Adam Fox
3
Bagaimana itu akan membuat loop tak terbatas? Ini dari deskripsi loadView di dokumentasi iOS. "Pengontrol tampilan memanggil metode ini ketika properti tampilan diminta tetapi saat ini nihil."
Johan
2
Mereferensikan ke self.view dalamloadView()inilah yang mengarah pada rekursi tak terbatas. Sebaliknya, menyetel tampilan tidak hanya diperbolehkan tetapi memang diperlukan (secara manual, atau dengan merangkai kesuper. Jika tidak, ia akan tetap dipanggil selama tampilan tersebutnil).
Nicolas Miari
29

Info.plist

tambahkan pengaturan keamanan transportasi Info.plist Anda

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

Xcode 9.1+

Menggunakan pembuat antarmuka

Anda bisa menemukan elemen WKWebView di perpustakaan Object.

masukkan deskripsi gambar di sini

Tambahkan tampilan secara terprogram dengan 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

Tambahkan tampilan secara terprogram dengan Swift 5 (sampel lengkap)

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)
    }
}
Bodnarchuk dengan mudah
sumber
Bukan saran yang baik untuk mengalokasikan tampilan baru di penginisialisasi untuk WebView. Tanggapan crx_au lebih unggul
Ilias Karim
Saya tidak menemukan hal lain yang berhasil !! Jadi ... seperti yang ILI4S katakan mungkin itu bukan saran yang bagus, saya tidak tahu apakah itu atau tidak, tetapi berfungsi dengan baik! Terima kasih kawan, Anda menyelamatkan hari saya !! :)
Jorge Cordero
20

Dengan Xcode 8 sekarang ini mungkin, tetapi cara untuk mencapainya sedikit rumit untuk sedikitnya. Tapi, hei, solusi yang berhasil adalah solusi yang berhasil, bukan? Biar saya jelaskan.

InitWithCoder WKWebView: tidak lagi dianotasi sebagai "NS_UNAVAILABLE". Sekarang terlihat seperti yang ditunjukkan di bawah ini.

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

Mulailah dengan membuat subkelas WKWebView dan mengganti initWithCoder. Alih-alih memanggil super initWithCoder, Anda harus menggunakan metode init yang berbeda, seperti initWithFrame: configuration :. Contoh cepat di bawah ini.

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

Di Storyboard Anda, gunakan UIView dan berikan kelas kustom dari subclass baru Anda. Sisanya adalah bisnis seperti biasa (menyetel batasan tata letak otomatis, menghubungkan tampilan ke outlet di pengontrol, dll).

Terakhir, WKWebView menskalakan konten secara berbeda dengan UIWebView. Banyak orang mungkin ingin mengikuti saran sederhana di Suppress WKWebView dari penskalaan konten untuk merender pada pembesaran yang sama seperti yang dilakukan UIWebView untuk membuat WKWebView lebih dekat mengikuti perilaku UIWebView dalam hal ini.

crx_au
sumber
2
itu harus dibaca self = [super initWithFrame:myFrame configuration:myConfiguration];juga jika Anda menggunakan batasan, jangan lupa untuk mengaturself.translatesAutoresizingMaskIntoConstraints = NO;
Mojo66
Daripada menggunakan batas layar utama sebagai bingkai placeholder, Anda juga dapat menggunakan CGRectZero dan menghemat beberapa kode.
Ilias Karim
Solusi bagus. Bekerja dengan baik.
Rayfleck
Bekerja dengan sempurna! Perbaikan bagus karena tidak harus Menargetkan iOS 11 untuk mendapatkan batasan WKWebView di storyboard.
mikemike396
20

Ini adalah versi Swift 3 sederhana berdasarkan jawaban crx_au yang sangat baik.

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

Buat UIView di Interface Builder, tetapkan batasan Anda, dan tetapkan WKWebView_IBWrappersebagai kelas khusus, seperti:

Utilitas -> Tab Identity Inspector [1]

Gamma
sumber
Jawaban luar biasa
Amr Hossam
6

Jika Anda masih menghadapi masalah ini di versi Xcode terbaru, yaitu v9.2 +, cukup impor Webkit ke ViewController Anda:

#import <WebKit/WebKit.h>
  1. Sebelum perbaikan: masukkan deskripsi gambar di sini

  2. Setelah perbaikan:

masukkan deskripsi gambar di sini

MrDEV
sumber
4

Ini sekarang tampaknya diperbaiki di Xcode 9b4. Catatan rilis mengatakan "WKWebView tersedia di perpustakaan objek iOS".

Saya belum melihat lebih dalam untuk melihat apakah itu membutuhkan iOS 11 atau kompatibel ke belakang.

EricS
sumber
Saya dapat mengonfirmasi bahwa ini berfungsi! Hore! Ini juga berfungsi di papan cerita macOS (setidaknya untuk aplikasi yang menargetkan macOS 10.13+).
Clifton Labrum
1

Anda dapat membuat instance dan mengkonfigurasi WKWebView di IB sejak Xcode 9, tidak perlu melakukannya dalam kode. masukkan deskripsi gambar di sini

Perhatikan bahwa target penerapan Anda harus lebih tinggi dari iOS 10 atau Anda akan mendapatkan kesalahan waktu kompilasi.

masukkan deskripsi gambar di sini

atineoSE
sumber
0

Dalam XCode Versi 9.0.1 WKWebView tersedia di Interface Builder.

ManuelMB
sumber
0

Saya telah menautkan WebKit, sekarang berfungsi!

contoh

zhou fajar
sumber
0

Tidak yakin apakah ini membantu tetapi saya memecahkan masalah untuk saya dengan menyertakan kerangka kerja WebKit untuk target. Jangan sematkan, cukup tautkan referensi. Saya masih menggunakan objek WebView di IB dan meletakkannya di ViewController tempat saya menyematkannya dan saya tidak pernah mengalami masalah ...

Saya telah mengerjakan 4 proyek MacOS WKWebView sekarang dan WebView telah bekerja dengan baik di setiap proyek.

ranTrek
sumber
-14

Ini berhasil untuk saya di Xcode 7.2 ...

Pertama tambahkan tampilan web sebagai outlet UIWebView di storyboard / IB. Ini akan memberi Anda properti seperti ini:

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

Kemudian edit kode Anda untuk mengubahnya menjadi WKWebView.

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

Anda juga harus mengubah kelas khusus menjadi WKWebView di inspektur Identitas.

Pat McG
sumber
Saya mencoba ini dengan proyek OS X - itu tidak berhasil, jadi itu pasti kasus khusus untuk iOS.
henrikstroem
2
Apa yang Anda lakukan sama seperti tipe pemain. Itu TIDAK bisa mengubah jenis webView sama sekali.
DawnSong