UITableViewCell With UIWebView Dynamic Height

时光怂恿深爱的人放手 提交于 2019-12-28 04:49:07

问题


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?


回答1:


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)
    }

    // ...
}



回答2:


It's work for me, easy Way to load Html String on WebView with dynamic.

First take textView in TableViewCell with scroll disable and then take WebView, Apply Zero constraint on all 4 Side with ContentView. Now give same height constraint to both textview and WebView.Now give same text to both view as shown below code.

For Clean UI Hide textView From XIB or storyBoard.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return 10
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return 100
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "tableviewcell") as! tableviewcell
    let theString : String = "</p><img src='https://pbs.twimg.com/profile_images/655066410087940096/QSUlrrlm.png' width=100 height=100 /><h2>Subheader</h2>"

    let theAttributedString = try! NSAttributedString(data: theString.data(using: String.Encoding.utf8, allowLossyConversion: false)!,options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType],  documentAttributes: nil)

    cell.textview.attributedText =  theAttributedString

    cell.webview.loadHTMLString(theString, baseURL: nil)

    return cell
}



回答3:


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)
    }
}



回答4:


After calculating the height of webview Use DispatchQueue for reloading the tableViewcell height DispatchQueue.main.async.It avoids abnormal empty spaces and crash while reloading webview frame

func webViewDidFinishLoad(_ webView: UIWebView)
{
    var frame : CGRect = webVwModule.frame;
    frame.size.height = 1;
    self.webVwModule.frame.size = webVwModule.sizeThatFits(.zero)
    frame.size = self.webVwModule.frame.size;
    webView.frame = frame;
    webViewContentHeight = self.webVwModule.frame.size.height;
    isWebViewLoaded = true

    DispatchQueue.main.async(execute: { () -> Void in
       self.tableView.beginUpdates()
        self.tableView.endUpdates()
    })
    }

override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {

        return webViewContentHeight!
}



回答5:


var heightOfWebview=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 CGFloat(220+heightOfWebview) /// 220 is my static value
}



回答6:


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
}



回答7:


The most easy and elegant way is

  1. Add height layout constraint for webview
  2. Add webview Delegate finished loading then set contentSize height to constant of height layout constraint.

  3. Keep instance of tableview or make a delegate - block - closure to main tableview.

  4. Call tableview beginupdate endupdate to let tableview know they should validate layout.

class WebViewTableViewCell: UITableViewCell {
    weak var viewController: ViewController? = nil
    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var heightLayoutConstraint: NSLayoutConstraint!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        webView.loadRequest(URLRequest(url: URL(string: "https://tinhte.vn")!))
        webView.delegate = self
        webView.scrollView.isScrollEnabled = false
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}
extension WebViewTableViewCell: UIWebViewDelegate {
    func webViewDidFinishLoad(_ webView: UIWebView) {
        heightLayoutConstraint.constant = webView.scrollView.contentSize.height
        viewController?.tableView.beginUpdates()
        viewController?.tableView.endUpdates()
    }
}



回答8:


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.




回答9:


class WebViewTableViewCell: UITableViewCell {
    weak var viewController: ViewController? = nil
    @IBOutlet weak var webView: UIWebView!
    @IBOutlet weak var heightLayoutConstraint: NSLayoutConstraint!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        webView.loadRequest(URLRequest(url: URL(string: "https://tinhte.vn")!))
        webView.delegate = self
        webView.scrollView.isScrollEnabled = false
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}
extension WebViewTableViewCell: UIWebViewDelegate {
    func webViewDidFinishLoad(_ webView: UIWebView) {
        heightLayoutConstraint.constant = webView.scrollView.contentSize.height
        viewController?.tableView.beginUpdates()
        viewController?.tableView.endUpdates()
    }
}



回答10:


Implement the UITableview delegate heightforrowatindexpath to return the webview frame height.



来源:https://stackoverflow.com/questions/32548771/uitableviewcell-with-uiwebview-dynamic-height

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!