如何确定一个UIWebView的内容大小?

我有一个UIWebView具有不同的(单页)内容。 我想找出内容的CGSize来适当调整我的父视图。 显然-sizeThatFits:不幸的是只返回webView的当前帧大小。

事实certificate,我的第一个猜测使用-sizeThatFits:并不完全错误。 它似乎工作,但只有在发送-sizeThatFits:之前,webView的框架设置为最小的大小。 之后,我们可以通过配件尺寸来纠正错误的框架尺寸。 这听起来很糟糕,但实际上并没有那么糟糕。 既然我们都是一个接一个地进行帧变化,那么视图就不会更新,也不会闪烁。

当然,我们必须等到内容被加载,所以我们把代码放到-webViewDidFinishLoad: delegate方法中。

 - (void)webViewDidFinishLoad:(UIWebView *)aWebView { CGRect frame = aWebView.frame; frame.size.height = 1; aWebView.frame = frame; CGSize fittingSize = [aWebView sizeThatFits:CGSizeZero]; frame.size = fittingSize; aWebView.frame = frame; NSLog(@"size: %f, %f", fittingSize.width, fittingSize.height); } 

我应该指出另一种方法 (谢谢@GregInYEG)使用JavaScript。 不确定哪个解决scheme性能更好。

我喜欢这个更好的两个hacky解决scheme。

我有另一个很好的解决scheme。

一方面,Ortwin的方法和解决scheme只适用于iOS 6.0及更高版本,但是无法在iOS 5.0,5.1和5.1.1上正常工作,另一方面也有一些我不喜欢也不能理解的东西用Ortwin的方法,就是使用参数CGSizeZero的方法[webView sizeThatFits:CGSizeZero] :如果你阅读苹果官方文档关于这个方法及其参数,它明确地说:

此方法的默认实现返回视图边界矩形的大小部分。 子类可以重写此方法以基于任何子视图的所需布局返回自定义值。 例如,UISwitch对象返回一个固定大小的值,该值代表切换视图的标准大小,而UIImageView对象则返回当前正在显示的图像的大小。

我的意思是,就像他没有任何逻辑地遇到他的解决scheme,因为阅读文档,传递给[webView sizeThatFits: ...]的参数应该至less具有所需的width 。 使用他的解决scheme,在调用带有CGSizeZero参数的CGSizeZero之前,将期望的宽度设置为webView的框架。 所以我保持这个解决scheme正在iOS 6上“机会”。

我想到了一个更合理的方法,其优点是适用于iOS 5.0及更高版本…而且在复杂情况下,多个webView(其属性webView.scrollView.scrollEnabled = NOembedded在scrollView

这里是我的代码强制的webView的布局到所需的width并获得相应的height设置回到webView本身:

 - (void)webViewDidFinishLoad:(UIWebView *)aWebView { aWebView.scrollView.scrollEnabled = NO; // Property available in iOS 5.0 and later CGRect frame = aWebView.frame; frame.size.width = 200; // Your desired width here. frame.size.height = 1; // Set the height to a small one. aWebView.frame = frame; // Set webView's Frame, forcing the Layout of its embedded scrollView with current Frame's constraints (Width set above). frame.size.height = aWebView.scrollView.contentSize.height; // Get the corresponding height from the webView's embedded scrollView. aWebView.frame = frame; // Set the scrollView contentHeight back to the frame itself. } 

请注意,在我的例子中, webView被embedded到具有其他webViews的自定义scrollView中…所有这些webViews都有它们的webViews webView.scrollView.scrollEnabled = NO ,我必须添加的最后一段代码是计算我的自定义scrollViewcontentSizeembedded这些webViews ,但它是一样简单,总结我的webViewframe.size.height计算与上述技巧…

复活这个问题,因为我发现Ortwin的答案只能工作大部分时间…

webViewDidFinishLoad方法可能会被调用多次,sizeThatFits返回的第一个值只是最终大小的一部分。 然后,无论出于什么原因,当webViewDidFinishLoad再次触发时,下一次调用sizeThatFits将不正确地返回与之前相同的值! 对于相同的内容,这会随机发生,就好像它是某种并发问题一样。 也许这种行为随着时间的推移已经改变了,因为我正在为iOS 5构build,并且还发现sizeToFit的工作方式非常相似(尽pipe以前不是这样?)。

我已经解决了这个简单的解决scheme:

 - (void)webViewDidFinishLoad:(UIWebView *)aWebView { CGFloat height = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.height"] floatValue]; CGFloat width = [[aWebView stringByEvaluatingJavaScriptFromString:@"document.width"] floatValue]; CGRect frame = aWebView.frame; frame.size.height = height; frame.size.width = width; aWebView.frame = frame; } 

Swift(2.2):

 func webViewDidFinishLoad(webView: UIWebView) { if let heightString = webView.stringByEvaluatingJavaScriptFromString("document.height"), widthString = webView.stringByEvaluatingJavaScriptFromString("document.width"), height = Float(heightString), width = Float(widthString) { var rect = webView.frame rect.size.height = CGFloat(height) rect.size.width = CGFloat(width) webView.frame = rect } } 

更新:我发现在评论中提到这似乎并没有赶上内容缩水的情况。 不知道是否所有的内容和操作系统版本是真的,试试看。

在Xcode 8和iOS 10中确定Web视图的高度。 你可以使用高度

 - (void)webViewDidFinishLoad:(UIWebView *)webView { CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue]; NSLog(@"Webview height is:: %f", height); } 

或Swift

  func webViewDidFinishLoad(aWebView:UIWebView){ let height: Float = (aWebView.stringByEvaluatingJavaScriptFromString("document.body.scrollHeight")?.toFloat())! print("Webview height is::\(height)") } 

一个简单的解决scheme是只使用webView.scrollView.contentSize但我不知道这是否适用于JavaScript。 如果没有使用JavaScript,可以肯定的是:

 - (void)webViewDidFinishLoad:(UIWebView *)aWebView { CGSize contentSize = aWebView.scrollView.contentSize; NSLog(@"webView contentSize: %@", NSStringFromCGSize(contentSize)); } 

AFAIK你可以使用[webView sizeThatFits:CGSizeZero]找出它的内容大小。

我正在使用不是子视图的UIWebView (因此不是窗口层次结构的一部分)来确定UITableViewCells的HTML内容的大小。 我发现断开的UIWebView不会正确地报告它的大小-[UIWebView sizeThatFits:] 。 此外,正如在https://stackoverflow.com/a/3937599/9636中所提到的,您必须将;UIWebViewframe height为1,以便获得适当的高度。

如果UIWebView的高度太大(即,您已将其设置为1000,但HTML内容大小只有500):

 UIWebView.scrollView.contentSize.height -[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"] -[UIWebView sizeThatFits:] 

全部返回1000的height

在这种情况下解决我的问题,我用https://stackoverflow.com/a/11770883/9636 ,我忠实地投票。 不过,当我的UIWebView.frame.width-[UIWebView sizeThatFits:] width同时,我只使用这个解决scheme。

这里没有任何build议帮助我了解我的情况,但是我读了一些能够给我答案的东西。 我有一个ViewController与一组固定的UI控件,后面跟着一个UIWebView。 我希望整个页面滚动,就好像UI控件连接到HTML内容,所以我禁用了UIWebView的滚动,然后必须正确设置父滚动视图的内容大小。

重要的提示原来是UIWebView直到渲染到屏幕上才正确报告它的大小。 所以,当我加载内容时,我把内容大小设置为可用的屏幕高度。 然后,在viewDidAppear我更新滚动视图的内容大小到正确的值。 这对我工作,因为我在本地内容上调用loadHTMLString。 如果使用loadRequest,则可能需要更新webViewDidFinishLoad中的contentSize,具体取决于检索html的速度。

没有闪烁,因为只有滚动视图的不可见部分被改变。

如果你的HTML包含像iframe那样大量的 HTML内容(例如facebook-,twitter,instagram-embeds),那真正的解决scheme就困难得多了,首先要包装你的HTML:

 [htmlContent appendFormat:@"<html>", [[LocalizationStore instance] currentTextDir], [[LocalizationStore instance] currentLang]]; [htmlContent appendFormat:@"<head>"]; [htmlContent appendString:@"<script type=\"text/javascript\">"]; [htmlContent appendFormat:@" var lastHeight = 0;"]; [htmlContent appendFormat:@" function updateHeight() { var h = document.getElementById('content').offsetHeight; if (lastHeight != h) { lastHeight = h; window.location.href = \"x-update-webview-height://\" + h } }"]; [htmlContent appendFormat:@" window.onload = function() {"]; [htmlContent appendFormat:@" setTimeout(updateHeight, 1000);"]; [htmlContent appendFormat:@" setTimeout(updateHeight, 3000);"]; [htmlContent appendFormat:@" if (window.intervalId) { clearInterval(window.intervalId); }"]; [htmlContent appendFormat:@" window.intervalId = setInterval(updateHeight, 5000);"]; [htmlContent appendFormat:@" setTimeout(function(){ clearInterval(window.intervalId); window.intervalId = null; }, 30000);"]; [htmlContent appendFormat:@" };"]; [htmlContent appendFormat:@"</script>"]; [htmlContent appendFormat:@"..."]; // Rest of your HTML <head>-section [htmlContent appendFormat:@"</head>"]; [htmlContent appendFormat:@"<body>"]; [htmlContent appendFormat:@"<div id=\"content\">"]; // !important https://stackoverflow.com/a/8031442/1046909 [htmlContent appendFormat:@"..."]; // Your HTML-content [htmlContent appendFormat:@"</div>"]; // </div id="content"> [htmlContent appendFormat:@"</body>"]; [htmlContent appendFormat:@"</html>"]; 

然后添加处理x-update-webview-height -scheme到你的shouldStartLoadWithRequest中

  if (navigationType == UIWebViewNavigationTypeLinkClicked || navigationType == UIWebViewNavigationTypeOther) { // Handling Custom URL Scheme if([[[request URL] scheme] isEqualToString:@"x-update-webview-height"]) { NSInteger currentWebViewHeight = [[[request URL] host] intValue]; if (_lastWebViewHeight != currentWebViewHeight) { _lastWebViewHeight = currentWebViewHeight; // class property _realWebViewHeight = currentWebViewHeight; // class property [self layoutSubviews]; } return NO; } ... 

最后在layoutSubviews中添加下面的代码:

  ... NSInteger webViewHeight = 0; if (_realWebViewHeight > 0) { webViewHeight = _realWebViewHeight; _realWebViewHeight = 0; } else { webViewHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.getElementById(\"content\").offsetHeight;"] integerValue]; } upateWebViewHeightTheWayYorLike(webViewHeight);// Now your have real WebViewHeight so you can update your webview height you like. ... 

PS你可以在你的ObjectiveC / Swift代码中实现延迟(SetTimeout和setInterval) – 这取决于你。

PSS有关UIWebView和Facebookembedded的重要信息: embedded式Facebookpost在UIWebView中不能正确显示

当使用webview作为子视图在scrollview的某处,你可以设置高度约束为一些常数值,然后使它出口,并使用它:

 - (void)webViewDidFinishLoad:(UIWebView *)webView { webView.scrollView.scrollEnabled = NO; _webViewHeight.constant = webView.scrollView.contentSize.height; } 

这很奇怪!

我testing了解决schemesizeThatFits:[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] 适合我。

不过,我发现了一个有趣的简单方法来获得网页内容的正确高度。 目前,我使用它在我的委托方法scrollViewDidScroll:

 CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame); 

在iOS 9.3模拟器/设备中validation,祝你好运!

编辑:

背景:HTML内容是通过我的stringvariables和HTTP内容模板来计算的,通过方法loadHTMLString:baseURL:加载,没有注册JS脚本。

对于iOS10,我得到了document.height 0(零)值,所以document.body.scrollHeight是在Webview中获取文档高度的解决scheme。 这个问题也可以通过width来解决。

我也坚持这个问题,然后我意识到,如果我想要计算的dynamic高度的webView,我需要先告诉webView的宽度,所以我在js之前添加一行,事实certificate,我可以得到非常准确的实际高度。

代码很简单,就像这样:

 -(void)webViewDidFinishLoad:(UIWebView *)webView { //tell the width first webView.width = [UIScreen mainScreen].bounds.size.width; //use js to get height dynamically CGFloat scrollSizeHeight = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue]; webView.height = scrollSizeHeight; webView.x = 0; webView.y = 0; //...... } 

同样在iOS 7中,所有提到的方法的正确工作添加到您的视图控制器viewDidLoad方法:

 if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) { self.automaticallyAdjustsScrollViewInsets = NO; } 

否则,这两种方法都不会像应该那样工作。

Xcode8 swift3.1:

  1. 首先将webView高度设置为0
  2. webViewDidFinishLoad委托中:

let height = webView.scrollView.contentSize.height

没有第一步,如果webview.height>实际的contentHeight,第2步将返回webview.height而不是contentize.height。