问题
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
- Add height layout constraint for webview
Add webview Delegate finished loading then set contentSize height to constant of height layout constraint.
Keep instance of tableview or make a delegate - block - closure to main tableview.
- 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