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?
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.
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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With