I'm using a UIWebView
for displaying content, in the form of an HTML string – not a website, higher than the screen of the iPhone, without needing to scroll in the webView itself, leaving that to the parent scrollView.
To achieve this, I need a way to get the total document size, including the scrollable area, to set the webView's height. I have tried a number of different Javascript solutions:
(document.height !== undefined) ? document.height : document.body.offsetHeight // Returns height of UIWebView
document.body.offsetHeight // Returns zero
document.body.clientHeight // Returns zero
document.documentElement.clientHeight // Returns height of UIWebView
window.innerHeight // Returns height of UIWebView -2
document.body.scrollHeight // Returns zero
Is there a solution that actually works?
Current (nonworking) code:
[[[self.singlePost.contentText subviews] lastObject] setScrollEnabled:NO];
int content_height = [[self.singlePost.contentText stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"] intValue];
NSLog(@"Content_height: %d", content_height);
CGRect rect = self.singlePost.contentText.frame;
rect.size.height = content_height;
self.singlePost.contentText.frame = rect;
There is no need to use Javascript in iOS 5.0 and up - you have direct, documented access to its scrollView:
- (void)webViewDidFinishLoad:(UIWebView *)webView {
CGFloat contentHeight = webView.scrollView.contentSize.height;
// ....
}
To get the total height of the contents of the webView.
When I tried with my code, I found,
(1) NSLog(@"webView height: %@", [webView stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"]);
(2) NSLog(@"webView height: %@", [webView stringByEvaluatingJavaScriptFromString: @"document.height"]);
(1)
return the height less than the original height. But (2)
return the actual height. My suggestion is to get the Max
of the two.
- (void)webViewDidFinishLoad:(UIWebView *)theWebView {
NSLog(@"Body height: %@", [webView stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"]);
NSLog(@"Doc height: %@", [webView stringByEvaluatingJavaScriptFromString: @"document.height"]);
NSString * javaScript = [NSString stringWithFormat:@"document.getElementById('%@').clientHeight", kDivID];
NSLog(@"Div height: %@",[webView stringByEvaluatingJavaScriptFromString:javaScript]);
[self reLayout];
}
- (CGFloat) getWebViewPageHeight {
CGFloat height1 = [[webView stringByEvaluatingJavaScriptFromString: @"document.height"] floatValue];
CGFloat height2 = [[webView stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"] floatValue];
return MAX(height1, height2);
}
Output
Body height: 485
Doc height: 509
Div height: 485
Where do you call your code?
For me it returns 0 if it is called right after the loadHTMLString Method.
If I call it in the (void)webViewDidFinishLoad:(UIWebView *)theWebView delegate, I get a valid value.
- (void)loadHTML: (NSString *)html {
webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
webView.delegate = self;
NSURL *resourceURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] bundlePath]];
[webView loadHTMLString:html baseURL: resourceURL];
NSLog(@"height: %d", [[webView stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"] intValue]); // returns 0
}
- (void)webViewDidFinishLoad:(UIWebView *)theWebView {
NSLog(@"height: %@", [webView stringByEvaluatingJavaScriptFromString: @"document.body.offsetHeight"]); //return 2166
}
I went with a slightly different approach, to create a <DIV> that I could key off of to get the size, because I was having no luck with inspecting document/body.
This is MonoTouch C#, but should work fine in Objective-C:
private const string DIV_ID = "_uiwebview_";
LoadHtmlString("<body style='background-color:#yourcolor; padding:0px; margin:0px'>" +
"<div style='width:" + Frame.Width + "px; padding:0px; margin:0px; font-family:" +
font.Name + "' id=" + DIV_ID + ">" + html + "</div></body>", base_url);
and getting the height in LoadFinished:
string sheight = EvaluateJavascript("document.getElementById('" + DIV_ID +
"').clientHeight");
@Jesse, this works when updating with HTML that would generate a smaller size than was previously shown.