How to determine UIWebView height based on content, within a variable height UITableView?

65,956

Solution 1

This code is probably too slow for table view use, but does the trick. It doesn't look like there's any alternative, as UIWebView offers no direct access to the DOM.

In a view controller's viewDidLoad I load some HTML in a webview and when the load is finished run some javascript to return the element height.

- (void)viewDidLoad
{
    [super viewDidLoad];
    webview.delegate = self;
    [webview loadHTMLString:@"<div id='foo' style='background: red'>The quick brown fox jumped over the lazy dog.</div>" baseURL:nil];
}

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    NSString *output = [webview stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"foo\").offsetHeight;"];
    NSLog(@"height: %@", output);
}

Solution 2

I was very glad to find your answers, the javascript trick worked well for me.

However, I wanted to say that there is also the "sizeThatFits:" method :

CGSize goodSize = [webView sizeThatFits:CGSizeMake(anyWidth,anyHeigth)];

We have to set a preferred size different from zero, but apart from that, it usually always works !

Usually, because with the UIWebViews, it seems to work only on the second loading (I use the "loadHTMLString:" method, and yes I call "sizeThatFits:" from the delegate "didFinishLoad:" method).

So, that's why I was very happy to find your solution which works in any case.

Solution 3

This seems to work. For now.

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
    CGFloat webViewHeight = 0.0f;
    if (self.subviews.count > 0) {
        UIView *scrollerView = [self.subviews objectAtIndex:0];
        if (scrollerView.subviews.count > 0) {
            UIView *webDocView = scrollerView.subviews.lastObject;
            if ([webDocView isKindOfClass:[NSClassFromString(@"UIWebDocumentView") class]])
                webViewHeight = webDocView.frame.size.height;
        }
    }
}

It should safely return 0 if it fails.

Solution 4

The better approach is to use scrollView.contentSize.height property, like below.

- (void)webViewDidFinishLoad:(UIWebView *)webView
{
     NSLog(@"%f",webView.scrollView.contentSize.height);   
}

Solution 5

The problem with -sizeThatFits: is that it doesn't work out of the box, at least not on iOS 4.1. It just returns the current size of the webView (no matter whether it's called with CGSizeZero or an arbitrary non-zero size).

I found out that it actually works if you reduce the frame height of the webView prior to calling -sizeThatFits:.

See my solution: How to determine the content size of a UIWebView?

Share:
65,956
frankodwyer
Author by

frankodwyer

Updated on July 05, 2022

Comments

  • frankodwyer
    frankodwyer almost 2 years

    I am trying to create a UITableView with variable height rows as explained in the answer to this question

    My problem is each cell contains a UIWebView with different (statically loaded) content I can't figure out how to calculate the proper height based on the content. Is there a way to do this? I've tried things like this:

       (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath {
           WebViewCell *cell = (WebViewCell*)[self tableView:tableView cellForRowAtIndexPath:indexPath];
           [cell setNeedsLayout];
           [cell layoutIfNeeded];
           return cell.bounds.size.height;
        }
    

    The cells themselves are loaded from a nib, which is simply a UITableViewCell containing a UIWebView. (It would also be fine if the cells just adjusted themselves to the largest of the html content, though variable height would be nicer).

  • frankodwyer
    frankodwyer about 15 years
    Sounds like it can be made work, however I've tried this in the table view and it returns an empty string (I guess because the webview had not finished loading). I'm thinking I could precompute this with an offscreen webview perhaps and cache the results for the tableview.
  • Erik B
    Erik B almost 14 years
    How is this better than: [webview stringByEvaluatingJavaScriptFromString:@"document.getElement‌​ById(\"foo\").offset‌​Height;"];? The problem is that the webview can't return its size until it has finished loading, which it might not have when the table needs to know its size.
  • Erik B
    Erik B almost 14 years
    This is almost exactly what I do. Although I am having a problem with the fact that the webview can't return its size until it has finished loading, which it might not have when the table needs to know its size. Does anyone have an idea of how to solve this?
  • BadPirate
    BadPirate over 13 years
    I used instead: NSString *output = [webView stringByEvaluatingJavaScriptFromString:@"document.body.scrol‌​lHeight;"];
  • Ortwin Gentz
    Ortwin Gentz about 13 years
    @Shade: See my answer how to make this work on newer iOS versions.
  • Shade
    Shade about 13 years
    thank you for the pointer. I did see your solution when I had this problem, but it doesn't work any better in my case. I don't really remember what I needed this for, but I did it in a different way in the end.
  • Dirty Henry
    Dirty Henry about 13 years
    With iOS 4.3 I had to do the following : the a tiny height for my webView (ie 1px) and do the call recommended by BadPirate and adjust both the scroll view's content value and the web view's frame value afterwards.
  • beetstra
    beetstra almost 12 years
    In my case it was not so much the CSS that was loaded late, but more specifically a font-file in the CSS.
  • Stan
    Stan almost 11 years
    That works! Thanks, I used before approach with javascript, but this one works better for me.
  • Vadoff
    Vadoff over 10 years
    You must set the height of the initial UIWebView to at least 1px, otherwise when making the JS call you'll get the screen height returned instead.
  • Andrey Gordeev
    Andrey Gordeev almost 8 years
    BE CAREFUL with this answer! Sometimes it returns wrong height! I'm getting wrong value when use it with many images
  • Itachi
    Itachi over 7 years
    For me, it's scrollView.contentSize.height - CGRectGetHeight(scrollView.frame). stackoverflow.com/a/39386880/1677041