产品中频繁遇到UITableViewCell含有WebView的需求,也提出好几个解决方案了,当然一次比一次简单。
旧方案
去年我总结出这个方案 完美解决 UITableViewCell 中加载 UIWebView 的高度计算问题 ,我的思路是:
- 获取数据,确定 tableView 的 cell 的数目和初始高度。
- 刷新 tableView,向每一个 cell 填充内容和初始高度,将初始高度赋值给 cell 的一个变量 cellHeight,并加载 webView。
- 等第 i 个 cell 中的 webView 加载完毕之后计算其高度 h。
- 令 h 与 cellHeight 进行比较。如果两个高度不等,通知 tableView 第 i 个 cell 的高度 h (即 cell 中 webView的实际高度),并调用如下代码刷新 cell:
tableView.reloadRows(at: [IndexPath (row: i, section: 0)], with: .none)
复制代码
如果相等,OK,第 i 个 cell 显示正确。
- 重复 3。
新方案
最近在做一个新的产品,又遇到了这个需求。本来我的想法是从上一个项目直接copy代码过来,但是看了半天觉得太过繁琐,再加上最近看了一些UITableViewCell自适应高度的文章,就想换种写法。
一般情况下,实现UITableViewCell自适应高度这样做:
- 设置UITableView自适应cell高度
tableView.estimatedRowHeight = 76
tableView.rowHeight = UITableView.automaticDimension
复制代码
- UITableViewCell设置从top到bottom完整的约束
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的自适应高度了。
但是对于webView,在开始加载时webView的高度并不固定,所以要在webView加载完毕后获取其高度并刷新cell。这一步就不用旧方案的step4来刷新cell了。
首先为webView监听webView加载:
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的高度。
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
// 当webview加载完成,计算并刷新高度
webView.evaluateJavaScript("document.body.scrollHeight") { (any, error) in
// height就是加载完毕的webView的高度
let height = any as! Int
}
}
复制代码
获取到高度后调整webView的高度:
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