計算WKWebView在Cell的高度
由於無法事先得知Web頁面的內容,所以這裡取得頁面高度要等到Web內容載入完成之後,再透過JavaScript去計算實際頁面高度。用WKNavigationDelegate的方法取得Web頁面高度:
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
webView.evaluateJavaScript("document.body.scrollHeight;") { (result, error) in
guard let h = result as? CGFloat else { return }
webView.frame.size.height = h
self.tableView.reloadData()
}
}
如果Web內容包含了圖片、影音或其他需要長時間載入之元件,光用以上的方法會需要很久的時間才能得到高度,使用者從畫面上得到的資訊就像是等了很久都完全沒有動作,所以為了讓使用者感受到畫面一直持續的在載入,這裡使用的方式是只要一有內容就計算高度,直到有新的內容載入完成再計算高度,藉此去解決等待畫面更新的問題。
實現的方式是透過WKWebView與JavaScript交互作用的特性,可以讓Web執行JavaScript的結果直接傳給APP端。一開始在iOS程式中先建立一個script message handler去關聯Web執行JavaScript:
webView.configuration.userContentController.add(self, name: "webCallBack")
接著在Web端的程式中加入"webCallBack",並且在每次執行時去回傳Web內容的高度去給APP:
function loadContent() {
var h = document.body.scrollHeight;
var dic = {"height" : h}
webkit.messageHandlers.webCallBack.postMessage(dic);
}
於是便可以讓Web一開始載入就先執行loadContent()這個函式,另外再在各個需要時間載入的元件加入這個函式,比如圖片:
<img src="http://path/source.jpg" onload="loadContent()">
都設置好之後,這時在APP端還要透過WKScriptMessageHandler方法才能接收到JavaScript的回傳結果,最後再根據回傳結果去做畫面高度的更新:
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
guard let body: NSDictionary = message.body as? NSDictionary else { return }
if let height = body["height"] as? CGFloat
webView.frame.size.height = height
self.tableView.reloadData()
}
}
另外如果要重複使用WKWebView去載入不同的Web內容,記得都要先初始化webView高度為0,之後再去取得最新高度。大部分問題用以上方法都可以解決。