Reputation: 3626
I ask this question because after some research, I haven't found satisfactory answers on the Web.
My need is simple, I have a UITableViewController, when I click on a cell, I need to display a loader (while loading the WKWebViewContent), THEN push the next UIViewController, with the WKWebView already loaded inside.
I tried this :
class TableViewController: UITableViewController, WKNavigationDelegate {
var webviewToLoad:WKWebView!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let htmlString = "some html content"
webviewToLoad = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
webviewToLoad.navigationDelegate = self
webviewToLoad.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "postview"{
let destinationController = segue.destination as! ViewController
destinationController.webView= webviewToLoad
}
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
print("Loaded!")
self.performSegue(withIdentifier: "postview", sender: self)
}
}
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
override func loadView() {
let webConfiguration = WKWebViewConfiguration()
webView = WKWebView(frame: .zero, configuration: webConfiguration)
webView.uiDelegate = self
self.view = webView
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
didFinish
is called, but the final WKWebView is blank.
Maybe it isn't the right way, any ideas?
Upvotes: 4
Views: 5354
Reputation: 3626
As @matt's answer was incomplete, here my solution to wait the webview loading before pushing the next view controller:
class TableViewController: UITableViewController, WKNavigationDelegate, WKUIDelegate {
var webviewToLoad:WKWebView!
var destinationController:ViewController!
var alert:UIAlertController!
override func viewDidLoad() {
super.viewDidLoad()
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
alert = UIAlertController(title: "Alert", message: "Loading", preferredStyle: .alert)
destinationController = UIStoryboard.init(name: "Main", bundle: Bundle.main).instantiateViewController(withIdentifier: "ViewController") as? ViewController
destinationController!.loadViewIfNeeded()
let webView:WKWebView = destinationController!.webView
webView.navigationDelegate = self
webView.uiDelegate = self
self.present(alert, animated: true, completion: nil)
let htmlString = "my html code"
webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
alert.dismiss(animated: false, completion: nil)
self.navigationController?.pushViewController(destinationController!, animated: true)
}
}
And the UIViewController with the webview inside:
class ViewController: UIViewController, WKUIDelegate, WKNavigationDelegate {
var webView: WKWebView!
@IBOutlet var viewForWebview: UIView!
@IBOutlet var heightWebviewConstraint: NSLayoutConstraint!
override func viewDidLoad() {
super.viewDidLoad()
}
override func loadView() {
super.loadView()
webView = WKWebView()
if (webView != nil) {
webView!.frame = viewForWebview.frame
webView.translatesAutoresizingMaskIntoConstraints = false
viewForWebview.addSubview(webView!)
NSLayoutConstraint.activate([
webView.topAnchor.constraint(equalTo: viewForWebview.topAnchor),
webView.bottomAnchor.constraint(equalTo: viewForWebview.bottomAnchor),
webView.leadingAnchor.constraint(equalTo: viewForWebview.leadingAnchor),
webView.trailingAnchor.constraint(equalTo: viewForWebview.trailingAnchor)
])
}
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
heightWebviewConstraint.constant = self.webView.scrollView.contentSize.height
self.view.setNeedsLayout()
self.view.setNeedsUpdateConstraints()
}
}
This code displays an UIAlertController during the webview loading, then dismiss the alert controller, and pushing the next controller, with the webview already loaded.
Upvotes: 3
Reputation: 534893
didFinish is called, but the final WKWebView is blank
Because you never did anything to make it not blank. Your code says:
var webviewToLoad:WKWebView!
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
webviewToLoad = WKWebView(frame: .zero, configuration: WKWebViewConfiguration())
webviewToLoad.navigationDelegate = self
webviewToLoad.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}
So everything you do is about webviewToLoad
. But webviewToLoad
is not the same webView
that appears in the ViewController after the segue:
class ViewController: UIViewController, WKUIDelegate {
var webView: WKWebView!
}
That is the web view you want to give content to. You are not doing that at all; none of your code touches webView
to give it content.
I think the heart of your confusion is here:
if segue.identifier == "postview"{
let destinationController = segue.destination as! ViewController
destinationController.webView = webviewToLoad
}
You cannot just substitute one web view for another and expect things to magically work; loadView
will still cause the original blank web view to be your view and to appear in the interface.
Instead, what you want is this architecture:
if segue.identifier == "postview"{
let destinationController = segue.destination as! ViewController
// make `loadView` run
destinationController.loadViewIfNeeded()
let webView = destinationController.webView
// now load _this_ `webView` with content!
let htmlString = "some html content"
webView.loadHTMLString(htmlString, baseURL: Bundle.main.resourceURL)
}
Upvotes: 2