views:

2715

answers:

3

What's the simplest, fastest, or otherwise (objectively) best way to add a couple of controls (e.g. some UIButtons) beneath a UIWebView?

To be clear, I'd like to display a regular scrolling UIWebView, but when scrolling reaches the bottom I'd like there to be some UIControls after the web content. I'd rather not fake it with HTML/CSS content that looks like a control; ideally they should be real controls that I can hook up to my view controller as usual.

I don't know whether it's easiest to try to do this with one big UIScrollView containing both the UIWebView and the controls (will there be scrolling conflicts between the UIScrollView and the nested UIWebView?), or with a UITableView containing the web view and controls in separate cells (will performance be terrible?), or in some other way that I haven't thought of.

Update: I don't imagine that I want the UIWebView itself to actually scroll; I thought I'd need to resize it to accommodate all of its content, disable its scrolling behaviour entirely, and then allow the user to scroll its parent view (either the UIScrollView or the UITableView) to reveal different parts of the UIWebView.

A: 

I don't believe there is any way to do this within the constraints of the public SDK.

Kevin Ballard
Oh dear. Would neither the big UIScrollView nor the UITableView work? Why not?
Tom Stuart
+2  A: 

Neither the UIScrollView nor UITableView solutions you proposed will work.

If you put the UIWebView in a UIScrollView, one or the other will intercept the scrolls and scroll its content pane, but the other will not. I'm not sure which one will, I think it would be the UIScrollView. In any case, there is no provision for the UIScrollView to scroll when you reach the end of scrolling in the UIWebView, or vice versa.

If you use a UITableView, the UIWebView will scroll inside its cell, but the UITableView won't scroll at all, or the UIWebView won't scroll at all, and the UITableView will. If you use the 'grouped' table style, it's possible that you could scroll the UIWebView and the UITableView, but it would not be the cohesive sort of experience you are looking for.

The only technique I can think of that might work is to muck around in the internals of the UIWebView and add your UIView containing buttons and whatnot to the scrolling entity used by the UIWebView. This is beyond my ken, but these header dumps will get you started. Keep in mind that if Apple notices what you're doing, they may reject your app, and additionally, the internals may change at any time, breaking your code. If you go this route, try to code it in such a way that missing functionality will cause a graceful failure.

EDIT:

With some discussion and experimenting, the OP and I have come to the conclusion that it is very possible, and there is a way to do it that doesn't rely on internals at all. That is, use an enclosing scroll view, and resize the web view once it has loaded to the full size of its own content view. This size can be found using [webView sizeThatFits:CGSizeZero].

If you did want to use UIWebView's privates to accomplish this, I have a short code example of adding a view to the UIWebView's document view, since I got it all worked out anyway :)

- (void)applicationDidFinishLaunching:(UIApplication *)application {    

 // Override point for customization after app launch 
 UIView* testView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
 UIWebView* testWebView = [[[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)] autorelease];
 [testView addSubview:testWebView];
 [testWebView setDelegate:self];
 [testWebView loadRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://google.com"]]];



 [window addSubview:testView];
 [window makeKeyAndVisible];
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
 UIView *insert = [[[UIView alloc] initWithFrame:CGRectMake(0, [[webView _documentView] frame].size.height, 320, 40)] autorelease];
 [insert setBackgroundColor:[UIColor greenColor]];
 [[webView _documentView] addSubview:insert];
}
mythogen
Thank you for the comprehensive and thoughtful answer. I don't want the UIWebView itself to scroll at all, though: I imagine resizing it to be large enough to display all of its content (i.e. several screens high), and just scrolling the parent view to reveal a different part of the large UIWebView (and eventually the controls beneath it). Is that not achievable?
Tom Stuart
Actually that may be achievable. You would have to load the request (with scalesPageToFit=NO), find out how tall the page is somehow, and reframe everything to fit that, within the contents of your own UIScrollView. The only problem I see is finding out how tall the page actually is. That itself might require mucking about in the internals; the UIWebView knows how tell its content view is, but I'm not sure there's an easy way to get it to tell you. I'm fiddling with some test code right now, I'll let you know how it goes.
mythogen
Brilliant. Thanks again. Does [webView sizeThatFits:CGSizeZero] not do the trick? (http://www.iphonedevsdk.com/forum/iphone-sdk-development/1388-getting-actual-content-size-uiwebview.html)
Tom Stuart
I don't know why you're asking me questions, you've got a better handle on this than I do :)That does indeed work. I also found that it's entirely trivial to add things directly to the webview's document view (as it is referred to in the dumped headers). I am editing the answer to include a code example of this.
mythogen
Thanks. I don't want to do anything underhand that would risk rejection from the App Store -- could you also please show your code example for the above-board technique with the UIScrollView?
Tom Stuart
I didn't get it working with UIScrollView, because I was focused on finding the size, not realizing you culd get it with sizeThatFits. While I was doing that I noticed you can just add it straight to the document view, and I decided to try that. This is not how I would recommend you do it, however, for the reason you mention. It should be fairly trivial to work out the scroll view code, but I can help with that if you need it.
mythogen
A: 

I tried out mythogen's suggestion of adding subview to uiwebview's documentview. However I cannot get any events out of it. Looks like the document view supresses all events. Do it happen that way, or is there a workaround? Thanks!