web-dev-qa-db-de.com

UITableViewCell mit dynamischer UIWebView-Höhe

Ich habe eine Tabellenansicht mit Zellen, die ein WebView enthalten. Ich möchte, dass die Höhe der Zelle der Höhe des WebView entspricht.

Dies ist der Code, den ich verwende: 

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

Und das ist das Ergebnis: https://postimg.cc/image/8qew1lqjj/

Die WebView hat die richtige Höhe, aber die Zelle ist nicht. Wie kann ich dieses Problem beheben?

16
OmerN

TableView ändert die Größe der Zellen selbst. Sie müssen lediglich die Delegat-Methode tableView(tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat implementieren.

Ja, Sie kennen die Höhe von WebView anfangs nicht, aber Sie können es berechnen und TableView bitten, die Zelle neu zu laden. Etwas wie das:

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

    // ...
}
22
ifau

Es ist eine Arbeit für mich, eine einfache Möglichkeit, HTML-String in WebView mit Dynamik zu laden.

Nehmen Sie zunächst textView in TableViewCell mit deaktiviertem Bildlauf und dann WebView, Zero-Constraint auf allen 4 Seiten mit ContentView. Geben Sie jetzt sowohl für textview als auch für WebView die gleiche Höhenbeschränkung. Geben Sie für beide Ansichten denselben Text ein, wie unter dem Code gezeigt. 

Für saubere Benutzeroberfläche verstecken Sie textView From XIB oder 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
Ujesh

Swift 4

ifau's Antwort für Swift 4 geändert, mit UITableView anstelle von UITableViewController

Nimm im Storyboard eine UITableView. Fügen Sie 1 Prototypzelle hinzu. Lassen Sie den reuseIdentifier der Zelle auf "cell". Ziehen Sie ein webView in die Zelle, und setzen Sie die Beschränkungen für führende, nachlaufende, obere und untere Begrenzung auf 0. Setzen Sie die Zellklasse auf TableViewCell

TableViewCell.Swift

Verbinden Sie den WebView-Ausgang mit dem 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

Verbinden Sie den tableView-Ausgang mit dem 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)
    }
}
2
Dia

Nach dem Berechnen der Höhe von Webview Verwenden Sie DispatchQueue , um die tableViewcell-Höhe DispatchQueue.main.async neu zu laden. Dadurch werden ungewöhnliche Leerzeichen und Abstürze beim erneuten Laden des Webview-Frames vermieden

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!
}
1
Sheereen S
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
}
0
Iya

Der beste Weg hat für mich funktioniert.

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
}
0
BatyrCan

Der einfachste und eleganteste Weg ist 

  1. Fügen Sie eine Höhenbeschränkung für die Webansicht hinzu
  2. Webview hinzufügen Delegate beendete das Laden und stellte dann die Höhe der contentSize auf die Konstante der Höhenbeschränkung des Layouts ein. 

  3. Behalten Sie die Instanz von tableview bei oder machen Sie eine Delegatenblockierung für die main tableview.

  4. Rufen Sie tableview beginupdate endupdate auf, um tableview mitzuteilen, dass das Layout überprüft werden soll.

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

0
Trung Phan

Ich habe eine weitere Lösung, die Sie berücksichtigen sollten. Machen Sie eine Höhenbeschränkung und verknüpfen Sie diese mit Ihrer UITableViewCell-Klasse. Implementieren Sie dann die Delegatmethode func webViewDidFinishLoad(_ webView: UIWebView) und setzen Sie die Höhenbeschränkung beim Aufruf auf webView.scrollView.contentSize.height.

0
Enrico Susatyo
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()
    }
}
0
Nitin