UITableViewCell с динамической высотой UIWebView

У меня есть табличный вид с ячейками, которые имеют в них webView, я хочу, чтобы высота ячейки соответствовала высоте webView.

Это код, который я использую:

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

И это результат: https://postimg.cc/image/8qew1lqjj/

WebView - это правильная высота, но ячейка не работает, как я могу исправить эту проблему?

Ответы

Ответ 1

TableView сама изменит размеры ячеек, вам просто нужно реализовать метод делегирования tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat.

Да, вы не знаете высоту 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)
    }

    // ...
}

Ответ 2

Это работает для меня, легко Способ загрузки Html String в WebView с динамическим.

Сначала возьмите textView в TableViewCell с отключением прокрутки, а затем возьмите WebView, примените ограничение Zero на всех 4 сторонах с ContentView. Теперь дайте одинаковое ограничение по высоте как для textview, так и для WebView. Теперь дайте одинаковый текст обоим представлениям, как показано ниже.

Для чистого пользовательского интерфейса Скройте textView Из XIB или 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, измененный для Swift 4, используя UITableView вместо UITableViewController.

В раскадровке возьмите UITableView. Добавьте к нему 1 прототипную ячейку. Храните идентификатор повторного использования ячейки в cell. Перетащите webView в ячейку и установите ограничения для верхнего, webView, верхнего и нижнего уровней на 0. Установите класс ячейки TableViewCell

TableViewCell.swift

Подключите 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

Подключите выход 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)
    }
}

Ответ 4

После вычисления высоты webview Использовать DispatchQueue для перезагрузки высоты таблицы tableView 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!
}

Ответ 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

Лучший способ работал для меня.

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

Самый простой и элегантный способ

  1. Добавить ограничение макета высоты для веб-просмотра
  2. Добавьте завершенную загрузку делегата веб-просмотра, затем установите contentSize height в константу ограничения высоты.

  3. Храните экземпляр tableview или создайте делегат-блок-закрытие в mainview.

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

Ответ 8

У меня есть еще одно решение, которое вы должны рассмотреть. Сделайте ограничение по высоте и привяжите его к классу UITableViewCell. Затем реализуем метод делегата func webViewDidFinishLoad(_ webView: UIWebView), и когда он вызывается, установите ограничение высоты равным 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

Внедрить делегат UITableview heightforrowatindexpath, чтобы вернуть высоту кадра webview.