Search code examples
iosxcodeswiftuitableviewuiwebview

UITableViewCell With UIWebView Dynamic Height


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:

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCellWithIdentifier("newsCell") as! NewsTableViewCell

    cell.webView.loadHTMLString("test<br>test<br>test<br>test<br>test<br>test", baseURL: nil)
    cell.webView.delegate = self

    var webFrame = cell.webView.frame
    var cellFrame = cell.frame
    cell.frame = CGRectMake(cellFrame.origin.x, cellFrame.origin.y, cellFrame.width, webFrame.height + 20)
    cell.backgroundColor = UIColor.redColor()

    return cell
}

func webViewDidFinishLoad(webView: UIWebView) {
    println("finished loading")
    var frame = webView.frame
    frame.size.height = 1
    webView.frame = frame

    var fittingSize = webView.sizeThatFits(CGSizeZero)
    frame.size = fittingSize
    webView.frame = frame

    var height: CGFloat = frame.height
    println(height)

    webView.frame = CGRectMake(frame.origin.x, frame.origin.x, frame.size.width, frame.size.height)

    newsTable.beginUpdates()
    newsTable.endUpdates()
}    

And this is the result: https://postimg.cc/image/8qew1lqjj/

The webView is the correct height but the cell isn't, How can I fix this problem?


Solution

  • TableView will resize cells itself, you just need implement tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat delegate method.

    Yes, you don't know the height of WebView initially, but you can calculate it and then ask TableView to reload cell. Something like this:

    class TableViewController: UITableViewController, UIWebViewDelegate
    {
        var content : [String] = ["test1<br>test1<br>test1<br>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 tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
        {
            let cell = tableView.dequeueReusableCellWithIdentifier("newsCell", forIndexPath: indexPath) as! NewsTableViewCell
            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 = CGRectMake(0, 0, cell.frame.size.width, htmlHeight)
    
            return cell
        }
    
        override func tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat
        {
            return contentHeights[indexPath.row]
        }
    
        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.reloadRowsAtIndexPaths([NSIndexPath(forRow: webView.tag, inSection: 0)], withRowAnimation: .Automatic)
        }
    
        // ...
    }