ios 具有 UIWebView 动态高度的 UITableViewCell

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/32548771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 07:37:01  来源:igfitidea点击:

UITableViewCell With UIWebView Dynamic Height

iosxcodeswiftuitableviewuiwebview

提问by OmerN

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.

我有一个表格视图,其中包含一个 webView 的单元格,我希望单元格的高度与 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/

这就是结果:https: //postimg.cc/image/8qew1lqjj/

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

webView 是正确的高度,但单元格不是,我该如何解决这个问题?

回答by ifau

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

TableView 会自行调整单元格的大小,您只需要实现tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat委托方法。

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:

是的,您最初不知道 WebView 的高度,但您可以计算它,然后让 TableView 重新加载单元格。像这样的东西:

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

    // ...
}

回答by Ujesh

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

它对我有用,在 WebView 上动态加载 Html 字符串的简单方法。

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.

首先在禁用滚动的 TableViewCell 中获取 textView,然后获取 WebView,使用 ContentView 在所有 4 个边上应用零约束。现在为 textview 和 WebView 提供相同的高度约束。现在为两个视图提供相同的文本,如下代码所示。

For Clean UI Hide textView From XIB or storyBoard.

对于干净的 UI 隐藏来自 XIB 或 storyBoard 的 textView。

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
}

回答by Dia

Swift 4

斯威夫特 4

ifau'sAnswer modified for Swift 4, using UITableViewinstead of UITableViewController.

ifau 的答案针对 Swift 4 进行了修改,使用UITableView代替UITableViewController.

In storyboard, take a UITableView. Add 1 prototype cell to it. Keep the reuseIdentifier of the cell to "cell". Drag a webViewinto the cell and set leading, trailing, top and bottom constraints to 0. Set the cell class to TableViewCell

在故事板中,取一个UITableView. 向其中添加 1 个原型单元格。保持单元格的重用标识符为“ cell”。将 awebView拖入单元格并将前导、尾随、顶部和底部约束设置为 0。将单元格类设置为TableViewCell

TableViewCell.swift

TableViewCell.swift

Connect webView outlet to storyboard:

将 webView 插座连接到故事板:

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

视图控制器.swift

Connect the tableView outlet to the storyboard:

将 tableView 插座连接到故事板:

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

回答by Sheereen S

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

计算完webview的高度后,使用DispatchQueue重新加载tableViewcell高度DispatchQueue.main.async,避免在重新加载webview框架时出现异常空白和崩溃

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

回答by BatyrCan

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
}

回答by Trung Phan

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.
  1. 为 webview 添加高度布局约束
  2. 添加 webview Delegate 完成加载然后将 contentSize 高度设置为高度布局约束的常量。

  3. 保留 tableview 的实例或对主 tableview 进行委托 - 阻止 - 关闭。

  4. 调用 tableview beginupdate endupdate 让 tableview 知道他们应该验证布局。

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

回答by Enrico Susatyo

I have one more solution that you should consider. Make a height constraint and link it to your UITableViewCellclass. 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.

我还有一个您应该考虑的解决方案。进行高度约束并将其链接到您的UITableViewCell班级。然后实现委托方法func webViewDidFinishLoad(_ webView: UIWebView),并在调用时将高度约束设置为等于webView.scrollView.contentSize.height

回答by Nitin

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

回答by Iya

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
}

回答by Martin Josephson

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

实现 UITableview 委托 heightforrowatindexpath 以返回 webview 框架高度。