Uitableviewcell with Uiwebview Dynamic Height

UITableViewCell With UIWebView Dynamic Height

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

// ...
}

UITableViewCell with UIWebview that adjusts height to content size

The auto layout approach might be tricky. An easier approach is to just set the frame of the corresponding cell in webViewDidFinishLoad. You can use cellForRowAtIndexPath on the table view to get the displayed cell (it won't try to get the cell from the UITableViewDataSource if it's already displayed because it'll be cached).

- (void)webViewDidFinishLoad:(UIWebView *)webView {
if (_contentHeights[webView.tag]) {
return;
}
float height = [NSNumber numberWithFloat:[[webView stringByEvaluatingJavaScriptFromString:@"document.body.offsetHeight;"] floatValue]];

NSIndexPath* indexOfCell = [NSIndexPath indexPathForRow:webView.tag inSection:0];
UITableViewCell* cell = [self.tableView cellForRowAtIndexPath:indexOfCell];
cell.frame = CGRectMake(0, 0, cell.frame.size.width, height);
}

UIWebView into a UITableViewCell with dynamic size

I still don't know why this is happing but I solved it using the following approach:

I moved [tableView beginUpdates] and [tableView endUpdates] instructions to webViewDidFinishLoad method. At this way, whenever webViewDidFinishLoad be executed, it will updated the cell size correctly. Although I don't think that is the best solution, it works.

Now, my webViewDidFinishLoad method looks like this:

- (void) webViewDidFinishLoad:(UIWebView *)aWebView {

CGRect frame = aWebView.frame;
frame.size.height = 1;
aWebView.frame = frame;
CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero];
frame.size = fittingSize;
aWebView.frame = frame;

self.cellSize = fittingSize.height;

[self.tableView beginUpdates];
[self.tableView endUpdates];

NSLog(@"Calling webViewDidFinishLoad. Cell size value: %lf", self.cellSize);

}

Perhaps the answer helps someone else with similar problems.

Dynamic UITableViewCell height for a cell that contains a UIWebView in iOS

I came up with my own solution. But thanks all the others who commented on this question and open my mind in different paths. So here what I did.

First added a UIWebViewDelegate to my ViewController class

@interface ViewController () <UITableViewDataSource, UITableViewDelegate, UIWebViewDelegate> {

Then loading HTML pages and adding delegate is done inside following method

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *cellIdentifier = @"TableCellID";

CustomTableViewCell *cell = (CustomTableViewCell *)[tableView dequeueReusableCellWithIdentifier:cellIdentifier];

if (cell == nil) {

NSArray *nibArray = [[NSBundle mainBundle] loadNibNamed:@"CustomTableViewCell" owner:self options:nil];
cell = [nibArray objectAtIndex:0];
}

cell.webView.delegate = self;
cell.webView.tag = indexPath.row;
cell.webView.scrollView.scrollEnabled = NO;

NSString *htmlFileName = [NSString stringWithFormat:@"page%ld", (long)indexPath.row];

NSString *htmlFile = [[NSBundle mainBundle] pathForResource:htmlFileName ofType:@"html"];
NSString *htmlString = [NSString stringWithContentsOfFile:htmlFile encoding:NSUTF8StringEncoding error:nil];
[cell.webView loadHTMLString:htmlString baseURL: [[NSBundle mainBundle] bundleURL]];

return cell;
}

After web view is loaded, calculate the size that fits to it's content and after all web views are loaded, I reload table data like below.

- (void)webViewDidFinishLoad:(UIWebView *)webView {

if (webView.tag == 0) {
[cellHeightMutArray removeAllObjects];
}

CGSize fittingSize = [webView sizeThatFits:CGSizeZero];

[cellHeightMutArray insertObject:@(fittingSize.height) atIndex:webView.tag];

if (((webView.tag + 1) == dataArray.count) && !reloadedTableViewAfterLoadingWebContent) {

reloadedTableViewAfterLoadingWebContent = YES;
_tableView.hidden = NO;

[_tableView reloadData];
}
}

Then I adjust the height of the cell (which was the main issue that I had)

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {

if (cellHeightMutArray.count > 0) {

return [[cellHeightMutArray objectAtIndex:indexPath.row] intValue];
}

return 44;
}

This is my solution and it works perfectly in iPhones and iPads.

But I had different issue when I run it with more complex user interface in iPads which is in my real project. I'll update this if my solutions for those issue related to this question.

Change UITableViewCell height based on webview content

Found a solution ...

  • In webViewDidFinishLoad(_ webView: UIWebView) set the constraint's
    height as in initial question but use document.body.clientHeight
  • Blast a notification to tell the associated tableview to not reloadData(), but rather beginUpdates() then endUpdates()

@objc func handleWebviewFinishedLoading() {
self.webview?.beginUpdates()
self.webview?.endUpdates()
}

This seems to redraw the cells without reloading them :)



Related Topics



Leave a reply



Submit