Ios 如何确定UIWebView的内容大小?

Ios 如何确定UIWebView的内容大小?,ios,iphone,cocoa-touch,uiwebview,uikit,Ios,Iphone,Cocoa Touch,Uiwebview,Uikit,我有一个具有不同(单页)内容的UIWebView。我想找出内容的CGSize,以适当调整父视图的大小。显而易见的-sizehatfits:不幸的是,它只返回了webView的当前帧大小。好吧,你可以使用[webView-sizehatfits:CGSizeZero]来计算它的内容大小。事实证明,我第一次使用-sizehatfits:的猜测并不是完全错误的。这似乎是可行的,但只有在发送-sizeThatFits:之前,将webView的框架设置为最小尺寸时,它才会起作用。之后,我们可以通过合适的尺

我有一个具有不同(单页)内容的
UIWebView
。我想找出内容的
CGSize
,以适当调整父视图的大小。显而易见的
-sizehatfits:
不幸的是,它只返回了webView的当前帧大小。

好吧,你可以使用
[webView-sizehatfits:CGSizeZero]
来计算它的内容大小。

事实证明,我第一次使用
-sizehatfits:
的猜测并不是完全错误的。这似乎是可行的,但只有在发送
-sizeThatFits:
之前,将webView的框架设置为最小尺寸时,它才会起作用。之后,我们可以通过合适的尺寸来纠正错误的框架尺寸。这听起来很糟糕,但实际上没那么糟糕。由于我们两个帧都在彼此之后进行更改,因此视图不会更新,也不会闪烁

当然,我们必须等待内容加载完毕,因此我们将代码放入
-webviewdiffinishload:
委托方法中

Obj-C

- (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);
}
- (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.
}
Swift 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
}
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;
}
我要指出的是(谢谢@GregInYEG)在使用JavaScript。不确定哪种解决方案性能更好


在两个黑客解决方案中,我更喜欢这一个。

重新提出这个问题,因为我发现Ortwin的答案在大多数情况下都是有效的

webviewdiffinishload
方法可能会被多次调用,而
sizehattfits
返回的第一个值只是最终大小的一部分。然后,无论出于何种原因,当再次激发
webViewDidFinishLoad
时,对
sizeThatFits
的下一次调用将错误地返回与之前相同的值!对于相同的内容,这将随机发生,就像是某种并发问题一样。也许随着时间的推移,这种行为已经发生了变化,因为我正在为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;
}
Swift(2.2):


更新:我发现正如评论中提到的,这似乎没有抓住内容缩水的情况。不确定它是否适用于所有内容和操作系统版本,请试一试。

我有另一个解决方案非常有效

一方面,Ortwin的方法和解决方案仅适用于iOS 6.0及更高版本,但无法在iOS 5.0、5.1和5.1.1上正常工作,另一方面,我不喜欢和不理解Ortwin的方法,这是使用方法
[webView sizeThatFits:CGSizeZero]
带有参数
CGSizeZero
:如果你阅读了苹果公司关于此方法及其参数的官方文档,它会清楚地说:

此方法的默认实现返回视图边框的大小部分。子类可以重写此方法,以基于任何子视图的所需布局返回自定义值。例如,UISwitch对象返回表示开关视图标准大小的固定大小值,UIImageView对象返回当前显示的图像大小

我的意思是,这就像他在没有任何逻辑的情况下遇到了他的解决方案,因为阅读文档时,传递给
[webView sizeThatFits:…]
的参数至少应该具有所需的
宽度。使用他的解决方案,在使用
CGSizeZero
参数调用
sizehatfits
之前,将所需的宽度设置为
webView
的框架。所以我认为这个解决方案是“偶然”在iOS 6上运行的

我设想了一种更合理的方法,它的优点是适用于iOS 5.0及更高版本。。。而且在复杂的情况下,
scrollView
中嵌入了多个webView(其属性为
webView.scrollView.scrollEnabled=NO

下面是我的代码,用于强制将
webView
的布局设置为所需的
宽度
,并将相应的
高度
设置回
webView
本身:

Obj-C

- (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);
}
- (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.
}
Swift 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
}
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
中,该视图具有其他
webView
…所有这些
webView
都有它们的
webView.scrollView.scrollEnabled=NO
,我必须添加的最后一段代码是计算
contentSize的
高度我的自定义
scrollView
的de>嵌入了这些
webView
,但这很容易,只要将我的
webView的
frame.size.height
相加,就可以用上面描述的技巧计算出来……

我使用的
UIWebView
不是子视图(因此不是窗口层次结构的一部分)要确定
UITableViewCells
的HTML内容大小,我发现断开连接的
UIWebView
无法使用
-[UIWebView sizeThatFits:]正确报告其大小
。此外,如中所述,您必须将
UIWebView
框架
高度
设置为1,才能获得正确的高度

如果
UIWebView
的高度太大(即设置为1000,但HTML内容大小仅为500):

全部返回1000的
高度


为了解决本例中的问题,我使用了,我尽职尽责地投了赞成票。但是,我仅在我的
UIWebView.frame.width
-[UIWebView sizethattfits:]相同时才使用此解决方案
width

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

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

同样在iOS 7中,为了正确使用所有提到的方法,请在视图控制器
viewDidLoad
方法中添加以下内容:

if ([self respondsToSelector:@selector(automaticallyAdjustsScrollViewInsets)]) {
    self.automaticallyAdjustsScrollViewInsets = NO;
}
否则,这两种方法都不起作用
    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;
    }
    ...
    ...
    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.
    ...
- (void)webViewDidFinishLoad:(UIWebView *)webView {
    webView.scrollView.scrollEnabled = NO;
    _webViewHeight.constant = webView.scrollView.contentSize.height;
}
CGFloat contentHeight = scrollView.contentSize.height - CGRectGetHeight(scrollView.frame);
- (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)")
    }