I have a UITableViewCell that has a UIWebView inside it. Data I load from the server has several comments containing rich HTML content(text, images, links, etc.) As the cell contains UIWebView, I have to wait till the entire content is loaded to get the height of the tableViewCell and update it.
The issue I'm running into is that as I scroll down the cells get updated and the whole view jerks and flickers. Basically, I'm looking for a way to preload the webviews to get their height beforehand. Also, this jerking only happens until all the cells have loaded the content since I'm storing the height of each cell locally.
Here's an example of the jittery experience.
Code of cellForRowIndex
open func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(indexPath: indexPath) as LiMessageDetailTableViewCell
cell.delegate = self
cell.cellModel = LiMessageDetailTableViewCellModel(data: messageObject.originalMessage, index: indexPath)
cell.heightOfWebView = messageObject.contentHeightsOriginalMessage[indexPath.row]
if messageObject.contentHeightsOriginalMessage[indexPath.row] != 0.0 {
cell.updateHeightConstrain()
}
return cell
}
WebView delegate method in TableViewCell
//MARK:- WEBVIEW DELEGATE
func webViewDidFinishLoad(_ webView: UIWebView) {
//This section resizes the webview according to the new content loaded.
var mframe = webView.frame
mframe.size.height = 1
webView.frame = mframe
let fittingSize = webView.sizeThatFits(.zero)
mframe.size = fittingSize
webView.frame = mframe
/**
I found that javascript gives a more accurate height when images are
included since they take more time loading than the normal content and
hence sizeThatFits does not always return proper result.
**/
let heightInString = webView.stringByEvaluatingJavaScript(from: "document.body.scrollHeight") ?? ""
guard let heightInFloat = Float(heightInString) else { return }
guard let index = cellModel?.indexPath else {return}
constrainHeightOfWebView.constant = fittingSize.height
guard let cellType = cellModel?.messageType else { return }
delegate?.updateHeight(index: index, newHeight: CGFloat(heightInFloat), cellType: cellType)
}
Delgate method which updates the height
func updateHeight(index: IndexPath, newHeight: CGFloat, cellType: LiMessageType) {
switch cellType {
case .originalMessage:
if msgObj.contentHeightsOriginalMessage[index.row] != 0.0 && msgObj.contentHeightsOriginalMessage[index.row] == newHeight {
return
}
msgObj.contentHeightsOriginalMessage[index.row] = newHeight
.....
}
self.tableView.beginUpdates()
self.tableView.endUpdates()
}
Another issue is that if the webview contains heavy images then the whole webview flickers as it reloads everytime the cell is dequeued, causing a bad experience.
Here's the example of webview with image reloading
The image issue resolves itself after some time as webview gets cached, but nevertheless a bad experience.
Is there a way to solve these issues?