Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determine UIWebView height based on dynamic local content, within a variable height TableViewCell

Okay, so I know this question has been asked and asked. There are many good suggestions, but I cannot get this to work as expected. I am trying to create a tableview cell that can dynamically set its height on load based on different html. What everyone suggests is to use the following method.

-(void)webViewDidFinishLoad:(UIWebView *)webView 

They say to calculate the height either using javascript as below:

NSString *output = [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight;"]; 

Or doing something like this (I created this):

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

Both of these methods return the correct height of the webview, but they happen after the tableview is initialized. This webViewDidFinishLoad gets called after heightForRowAtIndexPath method. So when the table is being built I dont have the height of the cell. So then everyone says well then just do a tableview reload inside your webViewDidFinishLoad which yet again does work, but I dont like this because there is a lag and it makes the scrolling of the tableview choppy when you get to that part. How can I fix this? And make it smooth? I was thinking of maybe somehow determining the webview height before loading the view, but not sure how I would do that. Also tried converting the html into a plain text string, but this results in a false height because the html has spaces and stuff while the plain text doesn't. Any help would be appreciated!

like image 933
mikemike396 Avatar asked May 24 '13 18:05

mikemike396


2 Answers

My suggestion is very similar to @Timothy Moose, by rendering the webview off screen.

The approach I would take here would be...

-(void)viewDidLoad
{
     //Create a UIWebView and store it in a property
     //Hook the delegate to the view controller.
     //Load the html string to the UIWebView.

     //The rest of your initialization
}

In this case, your heightForRowAtIndexPath: will still probably get called prior to the completion of the web view.

You can handle that in a couple of ways. Here's one suggestion.

In the delegate method of the UIWebView's webViewDidFinishLoading, check to make sure that the webview making the call is the webview stored in your property. If so, call to reload the section (or row) that your webview is contained in. This should call the heightForRowAtIndexPath: method to get called again, in which this case, you can store the height of the webview in the webViewDidFinishLoading callback.

If the cell is off screen when the view first shows, the cell that is created in cellForRowAtIndexPath:, should have the UIWebView that you created in your viewDidLoad. Do this by adding the UIWebView to the cell's content view.

If the cell is on screen when the view first shows, I would suggest an activity spinner the first time the cell is loaded, and then once the webview is done loading, reload the cell with the webview.

like image 197
DavidAndroidDev Avatar answered Nov 15 '22 16:11

DavidAndroidDev


At the end of the day you can't know the height of a webview's content until it loads. And if the same bit of code is setting up the table and loading the webview, the webview is always going to complete it's load after the table is already displayed.

If you repeatedly load the same HTML you could cache the height, but you're still going to have a problem the first time.

So the only way you're going to be able to display the scrolling tableview without being choppy is to have a default cell height until the webview has loaded. Then change it. But you've tried that, using reload. And that was choppy.

But what about it the cell height animates between the default hight and the true height? Maybe that would be more acceptable.

If you're only doing height changes, I believe you can do this rather than reload, in order to animate the resizing.

[tableView beginUpdates];
[tableView endUpdates];

Nothing needed between the two lines.

Maybe you could combine this with caching the true height of the HTML for next time the user scrolls it into view.

like image 25
Steve Waddicor Avatar answered Nov 15 '22 17:11

Steve Waddicor