產品中頻繁遇到UITableViewCell含有WebView的需求,也提出好幾個解決方案了,固然一次比一次簡單。html
去年我總結出這個方案完美解決 UITableViewCell 中加載 UIWebView 的高度計算問題,個人思路是:web
tableView.reloadRows(at: [IndexPath (row: i, section: 0)], with: .none)
複製代碼
若是相等,OK,第 i 個 cell 顯示正確。bash
最近在作一個新的產品,又遇到了這個需求。原本個人想法是從上一個項目直接copy代碼過來,可是看了半天以爲太過繁瑣,再加上最近看了一些UITableViewCell自適應高度的文章,就想換種寫法。ui
通常狀況下,實現UITableViewCell自適應高度這樣作:lua
tableView.estimatedRowHeight = 76
tableView.rowHeight = UITableView.automaticDimension
複製代碼
questionWebView.snp.makeConstraints { (make) in
make.edges.equalToSuperview().inset(UIEdgeInsets.init(top: 8, left: 16, bottom: 8, right: 16))
make.height.equalTo(60)
}
複製代碼
對於通常的view,這兩步以後就能夠實現cell的自適應高度了。spa
可是對於webView,在開始加載時webView的高度並不固定,因此要在webView加載完畢後獲取其高度並刷新cell。這一步就不用舊方案的step4來刷新cell了。調試
首先爲webView監聽webView加載:code
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
tableView.separatorStyle = .none
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as! ExerciseQuestionCell
// 爲cell設置數據
cell.setData(exerciseArray[indexPath.row])
// 監聽webView加載
cell.questionWebView.delegate = self
cell.selectionStyle = .none
return cell
}
複製代碼
獲取webView的高度。cdn
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// 當webview加載完成,計算並刷新高度
webView.evaluateJavaScript("document.body.scrollHeight") { (any, error) in
// height就是加載完畢的webView的高度
let height = any as! Int
}
}
複製代碼
獲取到高度後調整webView的高度:htm
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// 當webview加載完成,計算並刷新高度
webView.evaluateJavaScript("document.body.scrollHeight") { (any, error) in
// height就是加載完畢的webView的高度
let height = any as! Int
// 調整webView高度
loadingWebView.snp.updateConstraints { (make) in
make.height.equalTo(height)
}
// 刷新tableView
exerciseTable.beginUpdates()
exerciseTable.endUpdates()
}
}
複製代碼
到這裏效果就出來了
可是在這裏我發現當滑動table時模擬器會變得十分卡頓,調試發現ExerciseQuestionCell的setData(exercise)方法在一直被調用,setData方法以下:
func setData(_ exercise: Exercise) {
do {
let data = exercise.question.data(using: .utf8)
let questionObject = try JSON.init(data: data!)
let question = questionObject["question"].stringValue
let questionHtml = DIV_HEAD + question + DIV_FOOT
webView.loadHTMLString(htmlString, baseURL: nil)
} catch {
print(error)
}
}
複製代碼
我想多是刷新tableView的時候調用setData方法,setData裏面調用webView.loadHTMLString方法加載html,加載完畢後又刷新tableView......產生循環,因此我在ExerciseQuestionCell裏面設置了一個變量loadedData來記錄cell是否設置過數據,若是設置過數據就再也不設置了:
func setData(_ exercise: Exercise) {
if loadedData {
// 設置過數據以後就再也不設置,防止屢次刷新
return
}
do {
let data = exercise.question.data(using: .utf8)
let questionObject = try JSON.init(data: data!)
let question = questionObject["question"].stringValue
let questionHtml = DIV_HEAD + question + DIV_FOOT
questionWebView.loadHtmlString(questionHtml)
} catch {
print(error)
}
loadedData = true
}
複製代碼
這樣一來就很清爽了。