我有一个UIWebView
不同的内容(单页)。我想找出CGSize
的内容,以适当地调整父视图的大小。-sizeThatFits:
不幸的是,显而易见的只是返回了webView的当前帧大小。
我有一个UIWebView
不同的内容(单页)。我想找出CGSize
的内容,以适当地调整父视图的大小。-sizeThatFits:
不幸的是,显而易见的只是返回了webView的当前帧大小。
Answers:
原来,我的第一个猜测-sizeThatFits:
并不完全是错误的。似乎可行,但前提是在发送之前将webView的框架设置为最小尺寸-sizeThatFits:
。之后,我们可以通过合适的尺寸来校正错误的框架尺寸。这听起来很糟糕,但实际上还不错。由于我们两个帧都紧接彼此更改,因此视图不会更新,也不会闪烁。
当然,我们必须等到内容加载完毕后,才能将代码放入-webViewDidFinishLoad:
委托方法中。
对象
- (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);
}
斯威夫特4.x
func webViewDidFinishLoad(_ webView: UIWebView) {
var frame = webView.frame
frame.size.height = 1
webView.frame = frame
let fittingSize = webView.sizeThatFits(CGSize.init(width: 0, height: 0))
frame.size = fittingSize
webView.frame = frame
}
我应该指出还有另一种使用JavaScript的方法(感谢@GregInYEG)。不知道哪种解决方案效果更好。
在两种hacky解决方案中,我更喜欢这种解决方案。
UIWebView
视图高于父视图,则需要将其嵌入UIScrollView
。
我有另一个很好的解决方案。
一方面,Ortwin的方法和解决方案仅适用于iOS 6.0及更高版本,但无法在iOS 5.0、5.1和5.1.1上正常工作,另一方面,我有些不喜欢且无法理解的内容使用Ortwin的方法时,将使用[webView sizeThatFits:CGSizeZero]
带有参数的方法CGSizeZero
:如果您阅读了有关此方法及其参数的Apple官方文档,则说明清楚:
此方法的默认实现返回视图边界矩形的大小部分。子类可以重写此方法以基于任何子视图的所需布局返回自定义值。例如,一个UISwitch对象返回一个固定的大小值,该值表示开关视图的标准大小,而UIImageView对象返回一个其当前显示的图像的大小。
我的意思是,就像他遇到了没有任何逻辑的解决方案一样,因为阅读文档,传递给它的参数[webView sizeThatFits: ...]
至少应该具有期望的width
。与他的溶液,所需的宽度被设定为webView
调用之前的帧sizeThatFits
与CGSizeZero
参数。因此,我认为此解决方案可以通过“机会”在iOS 6上运行。
我想象过一种更合理的方法,它的优势是可以在iOS 5.0及更高版本上使用...以及在复杂的情况下,多个webView(及其属性webView.scrollView.scrollEnabled = NO
嵌入到)中scrollView
。
这是我的代码,可将的Layout强制webView
设置为所需的Layout,width
并将对应的height
set返回其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.
}
斯威夫特4.x
func webViewDidFinishLoad(_ aWebView: UIWebView) {
aWebView.scrollView.isScrollEnabled = false
var frame = aWebView.frame
frame.size.width = 200
frame.size.height = 1
aWebView.frame = frame
frame.size.height = aWebView.scrollView.contentSize.height
aWebView.frame = frame;
}
请注意,在我的例子中,webView
被嵌入到定制scrollView
具有其它webViews
......所有这些webViews
有他们webView.scrollView.scrollEnabled = NO
,并且代码的最后一块,我不得不添加了的计算height
的contentSize
我的自定义的scrollView
嵌入这些webViews
,但它是那么容易用上述技巧将我webView
的frame.size.height
计算结果相加...
-[UIWebView scrollView]
仅在iOS 5.0或更高版本中可用。
重新提出这个问题,因为我发现Ortwin的答案在大多数情况下只起作用...
webViewDidFinishLoad
可能会多次调用该方法,并且返回的第一个值sizeThatFits
只是最终大小应占的一部分。然后,不管出于什么原因,以在下次调用sizeThatFits
时webViewDidFinishLoad
再次开火会错误地返回之前也做了同样的价值!对于相同的内容,这将是随机发生的,就像某种并发问题一样。也许这种行为随着时间的流逝而发生了变化,因为我正在为iOS 5进行构建,并且还发现它的sizeToFit
工作方式几乎相同(尽管以前没有这样做?)
我已经解决了这个简单的解决方案:
- (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;
}
迅捷(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
}
}
更新:我发现如评论中所述,这似乎并没有解决内容缩小的情况。不确定所有内容和操作系统版本是否正确,请尝试一下。
webView.scalesPageToFit = YES
上述评论中提到的@Sijo时有效。
在Xcode 8和iOS 10中确定Web视图的高度。你可以用
- (void)webViewDidFinishLoad:(UIWebView *)webView
{
CGFloat height = [[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"] floatValue];
NSLog(@"Webview height is:: %f", height);
}
或为斯威夫特
func webViewDidFinishLoad(aWebView:UIWebView){
let height: Float = (aWebView.stringByEvaluatingJavaScriptFromString("document.body.scrollHeight")?.toFloat())!
print("Webview height is::\(height)")
}
真奇怪
我测试的解决方案,既sizeThatFits:
和[webView stringByEvaluatingJavaScriptFromString:@"document.body.scrollHeight"]
被不为我工作。
但是,我找到了一种有趣的简单方法来获得正确的网页内容高度。目前,我在委托方法中使用了它scrollViewDidScroll:
。
CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
已在iOS 9.3模拟器/设备中验证,祝您好运!
编辑:
背景:html内容是由我的字符串变量和HTTP内容模板计算的,并由method加载的loadHTMLString:baseURL:
,那里没有注册的JS脚本。
我使用的UIWebView
不是子视图(因此也不是窗口层次结构的一部分)来确定的HTML内容的大小UITableViewCells
。我发现断开连接后UIWebView
无法使用正确报告其大小-[UIWebView sizeThatFits:]
。另外,如https://stackoverflow.com/a/3937599/9636中所述,您必须将UIWebView
s 设置frame
height
为1才能获得正确的高度。
如果UIWebView
的高度太大(即您将其设置为1000,但是HTML内容大小仅为500):
UIWebView.scrollView.contentSize.height
-[UIWebView stringByEvaluatingJavaScriptFromString:@"document.height"]
-[UIWebView sizeThatFits:]
全部返回height
1000。
为了解决这种情况下的问题,我使用了https://stackoverflow.com/a/11770883/9636,我已将其投了赞成票。但是,仅当我UIWebView.frame.width
与相同时,才使用此解决方案-[UIWebView sizeThatFits:]
width
。
这里的建议都没有帮助我解决我的情况,但是我读到的东西确实给了我答案。我有一个ViewController,带有一组固定的UI控件,然后是UIWebView。我希望整个页面都可以滚动,就像UI控件已连接到HTML内容一样,因此我禁用了UIWebView上的滚动,然后必须正确设置父级滚动视图的内容大小。
重要的提示是UIWebView在呈现到屏幕之前无法正确报告其大小。因此,当我加载内容时,我将内容大小设置为可用的屏幕高度。然后,在viewDidAppear中,将scrollview的内容大小更新为正确的值。这对我有用,因为我正在本地内容上调用loadHTMLString。如果您正在使用loadRequest,则可能还需要更新webViewDidFinishLoad中的contentSize,具体取决于html检索的速度。
没有闪烁,因为只更改了滚动视图的不可见部分。
webViewDidFinishLoad
作为安全的方法。
如果您的HTML包含大量的 HTML内容(例如iframe)(例如,facebook-,twitter,instagram-embeds),则真正的解决方案要困难得多,请先包装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和Facebook Embeds的重要信息:嵌入式Facebook帖子未在UIWebView中正确显示
我也遇到了这个问题,然后我意识到,如果我想计算webView的动态高度,我需要先告诉webView的宽度,因此我在js之前添加了一行,结果我可以非常准确的实际高度。
代码很简单,像这样:
-(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;
}
否则,这两种方法都无法正常工作。