How To Place a UIWebView inside a UIScrollView

To display several pieces of content on a screen, I needed several views. A scroll view (UIScrollView) was necessary to encompass the headline, photo and story text; I had the headline and photo at the top in a fixed area, but the content was of variable size as the story length changed.

Originally I had a text view (UITextView) to hold the story, but I wanted to do rich-text formatting, and since my database already used HTML to do italic and bold markup, a web view (UIWebView) was the obvious fit.

However, there are some caveats to using web views, most importantly to do with getting the size of the view after you’ve set the content. First, you must make sure the content has completed loading before you retrieve the size; you can do this in the delegate handlerwebViewDidFinishLoading:

Secondly, web views don’t respond correctly to sizeToFit: so you must do some more manual labor using a Javascript call to find the size of the web view after you’ve inserted the content. Some comments on other web sites mentioned that you can try [webView sizeThatFits:CGSizeZero] but this did not work for me.

Here’s the pertinent code from my current project. Also please note that I have a <div id="body"> surrounding my HTML content that I pass into the view. The javascript call uses this to grab the height of the web view after it loads. You’ll also notice that this calculation sometimes falls a little short so I add 12 points to it.

The code below creates a UIButton beneath the text copy, so I added 70 pixels to the contentSize of the enclosing scroll view. It works perfectly for me; hopefully it helps someone else, too.

If there’s a more kosher way to do it, I’d love to hear it. I had considered putting everything (including the headline and photo) inside the UIWebView, but then I would not have been able to have a UIButton beneath/outside it off screen; nor, more importantly would I be able to use my custom NetImageViewer class on the photo. (More on that later.)

#pragma mark -
#pragma mark UIWebViewDelegate methods 
-(void)webViewDidFinishLoad:(UIWebView *)webView{
	if (webView!=bioWebView)return;

	float h;
	
	NSLog(@"web view is %f high", bioWebView.frame.size.height);
	NSString *heightString = [bioWebView stringByEvaluatingJavaScriptFromString:@"document.getElementById("body").offsetHeight;"];
	NSLog(@"web content is %@ high",heightString);
	
	h = [heightString floatValue] +12.0f; // convert from string to float plus some extra points because calculation is sometimes one line short
	
	bioWebView.frame = CGRectMake(bioWebView.frame.origin.x, bioWebView.frame.origin.y, bioWebView.frame.size.width, h);
	
	// get bottom of text field
	h = bioWebView.frame.origin.y + h + 70; // extra 70 pixels for UIButton at bottom and padding.
	[scrollView setContentSize:CGSizeMake(320, h)];
	
	/* 

        position button code here.... 

        */

}

This entry was posted in iPhone Development, Programming and tagged , , , , . Bookmark the permalink.

15 Responses to How To Place a UIWebView inside a UIScrollView

  1. alec says:

    Also, I almost forgot to add: but web views scroll as well as scroll views, so you will have to come up with a technique to disable scrolling on the UIWebView so that only the UIScrollView responds to touches. After trying many of the suggestions I found on the web to no avail, I discovered that by setting userContentEnabled to NO on the web view solved my problem. Here’s the part of my view controller’s viewDidLoad: method where I stuff the content HTML with javascript into the web view, then turn off scrolling. NOTE: this will probably disable any links you have in the HTML but since I am only using this to format content, this works great for my purposes.


    NSString *html = [NSString stringWithFormat: @"<html><head></head><body><div id='body'>%@</div></body></html>",[entity objectForKey: @"bio"]];
    [bioWebView loadHTMLString:html baseURL:nil];
    bioWebView.userInteractionEnabled = NO;

  2. alec says:

    Ooh, here’s an even better way I found than setting userContentEnabled = NO that lets you keep the interaction enabled if you want hyperlinks to work:

    [[[bioWebView subviews] lastObject] setScrollEnabled:NO];

  3. Pingback: How To Place a UIWebView inside a UIScrollView « The Official Blog of Web X.0 Media

  4. Peter says:

    Very useful. Thanks for sharing how to do that.
    Worked great.

  5. Andy K says:

    Excellent, this has helped me a lot

    Cheers

  6. Mike says:

    That’s great, thank you!

  7. Nice nice nice, having the same case right now. Haven’t found any good solution for now about the scroll issues but what you wrote helpt me a lot 🙂 Thanks you~ !

  8. rbfigueira says:

    Hi,

    Can you please provide any sample code UIWebView inside a UIScrollView ?
    Thanks

  9. Rok says:

    Hello! Good work!

    As for that 12 px that you’re adding: you should use
    scrollHeight instead of offsetHeight.

    Regards,

    rok

  10. Andy says:

    You don’t need javascript, you can call sizeToFit on your webview, then just call bounds.size and the size will be correct.

  11. Yang says:

    thks, It’s help a lot!

  12. Imran Naseem says:

    Hello,

    Thanx for the code…

  13. Pingback: 嵌入在UIScrollView中的UIWebview不会滚动 - iOS问答 - 开发者第940464个问答

  14. Alain says:

    +1 +1 +1 +1= that’s perfect

  15. Al says:

    I am working on a project that implements something similar.

    We have a webview that is resized to the height of the content and a couple uiViews below the web view, all inside a UIScrollView. This works pretty well visually.

    The problem for us is that once the content is beyond a certain height, even with just text in the web content. The app crashes after a memory pressure warning.

    Have you encountered any memory errors with your approach?

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.