I have a table view with cells that have a webView in them, I want the height of the cell to match the height of the webView.
This is the code I use:
Implement the UITableview delegate heightforrowatindexpath to return the webview frame height.
The best way worked for me.
var heightOfWebview: CGFloat = 0
func webViewDidFinishLoad(_ aWebView: UIWebView)
{
var frame: CGRect = aWebView.frame
frame.size.height = 1
aWebView.frame = frame
let fittingSize = aWebView.sizeThatFits(CGSize.zero)
frame.size = fittingSize
aWebView.frame = frame
heightOfWebview = Int(fittingSize.height)
tableView.beginUpdates()
tableView.endUpdates()
print("Calling webViewDidFinishLoad. Cell size value: \(heightOfWebview)")
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
return heightOfWebview
}
Swift 4
ifau's Answer modified for Swift 4, using UITableView
instead of UITableViewController
.
In storyboard, take a UITableView
. Add 1 prototype cell to it. Keep the reuseIdentifier of the cell to "cell
". Drag a webView
into the cell and set leading, trailing, top and bottom constraints to 0. Set the cell class to TableViewCell
TableViewCell.swift
Connect webView outlet to storyboard:
import UIKit
class TableViewCell: UITableViewCell {
@IBOutlet weak var webView: UIWebView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}
ViewController.swift
Connect the tableView outlet to the storyboard:
import UIKit
class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource, UIWebViewDelegate {
@IBOutlet weak var tableView: UITableView!
var content : [String] = ["test1<br>test1<br>test1", "test22<br>test22<br>test22<br>test22<br>test22<br>test22"]
var contentHeights : [CGFloat] = [0.0, 0.0]
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
tableView.dataSource = self
tableView.delegate = self
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
return content.count
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
let cell : TableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as! TableViewCell
let htmlString = content[indexPath.row]
let htmlHeight = contentHeights[indexPath.row]
cell.webView.tag = indexPath.row
cell.webView.delegate = self
cell.webView.loadHTMLString(htmlString, baseURL: nil)
cell.webView.frame = CGRect(x: 0, y: 0, width: cell.frame.size.width, height: htmlHeight)
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if contentHeights[indexPath.row] != 0 {
return contentHeights[indexPath.row]
}
}
public func webViewDidFinishLoad(_ webView: UIWebView){
if (contentHeights[webView.tag] != 0.0)
{
// we already know height, no need to reload cell
return
}
contentHeights[webView.tag] = webView.scrollView.contentSize.height
tableView.reloadRows(at: [IndexPath(row: webView.tag, section: 0)], with: .automatic)
}
}
I have one more solution that you should consider. Make a height constraint and link it to your UITableViewCell
class. Then implement the delegate method func webViewDidFinishLoad(_ webView: UIWebView)
, and when it is called set the height constraint to be equal to webView.scrollView.contentSize.height
.