0

假设我有一个 UIWebView 与 UIImageView (或其他视图)堆叠:

在此处输入图像描述

我想调整 UIWebView 的大小,以便知道将 UIImageView 放在哪里。我这样做的方式是等待 UIWebView 完成加载:

webViewCalculating = YES;
while (webViewCalculating == YES) {
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}

然后我根据这个建议在 UIWebView 完成加载后调整它的大小:

-(void)webViewDidFinishLoad:(UIWebView *)webView
{
    CGRect frame = webView.frame;
    frame.size.height = 1;
    webView.frame = frame;

    CGSize fittingSize = [webView sizeThatFits:CGSizeZero];
    frame.size = fittingSize;
    webView.frame = frame;

    heightSoFar += webView.frame.size.height;
    webViewCalculating = NO;
}

在此之后,我会知道我的 UIWebView 有多高,我可以相应地放置我的 UIImageView。然而,当我推动另一个视图控制器并回到这个时,我的 hacky[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode似乎并没有等到我的 webView 先完成计算高度。有没有更好的方法让我知道我的 UIWebView 的大小而无需等待它加载?也许类似于sizeWithFontNSString 的方法?

4

2 回答 2

4

你不应该做你的 while 循环来抽运行循环。这是一个非常糟糕的主意。当 webview 完成加载时,您应该让滚动视图容器响应并重新布局子视图。从“大小合理的 webview 区域”开始。也许在加载网页内容时显示一个微调器。

我用来做到这一点的技术如下:

首先在 UIWebView 中添加一些分类方法如下:

@interface UIWebView (ContentSize)
- (CGFloat)documentOffsetHeight;
@end

@implementation UIWebView (ContentSize)
- (CGFloat)documentOffsetHeight
{
  return [[self stringByEvaluatingJavaScriptFromString:@"document.documentElement.offsetHeight"] floatValue];
}
@end

然后我编写了一个包含 UIWebView 的 UIView 子类。例如:

@interface MyWebView : UIView <UIWebViewDelegate>
@end

@implementation MyWebView 
{
    BOOL _loaded;
    UYIWebView *_webView;
}

- (id)initWithFrame:(CGRect)frame
{
  self = [super initWithFrame:frame];
  if (self)
  {
     _webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, 1)];
     _webView.delegate = self;
     _webView.alpha = 0.0f;
     [self addSubview:_webView]
   }
}

- (CGSize)sizeThatFits:(__unused CGSize)size
{
  if (_loaded)
  {
    CGFloat height = [webView_ documentOffsetHeight];
    CGFloat width = self.frame.size.width;
    return CGSizeMake(width, height);
  }

  return self.frame.size;
}

- (void)sizeToFit
{
  CGSize fittingSize = [self sizeThatFits:CGSizeZero];
  self.bounds = CGRectMake(0, 0, fittingSize.width, fittingSize.height);
}

- (void)layoutSubviews
{
  [super layoutSubviews];
  _webView.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height);
}

- (void)loadHTMLString:(NSString *)htmlString baseURL:(NSURL *)baseURL
{    
  // This code assumes jQuery is already used in the HTML content.  If not, added it as a script resource here too.
  NSString *scriptTag = @"<script type=\"text/javascript\" >jQuery(document).ready(function() { window.location = 'x-webview://ready'; });</script>\n";

  NSString *const headOpeningTag = @"<head>";
  if ([htmlString rangeOfString:headOpeningTag].location != NSNotFound )
  {
    htmlString = [htmlString stringByReplacingOccurrencesOfString:headOpeningTag
                                                       withString:[headOpeningTag stringByAppendingString:headContent]
                                                          options:NSCaseInsensitiveSearch
                                                            range:NSMakeRange(0, [htmlString length])];
  }
  else
  {
    htmlString = [headContent stringByAppendingString:htmlString];
  }

  [_webView loadHTMLString:htmlString baseURL:baseURL];
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
  if ([request.URL.scheme isEqualToString:@"x-webview"] && [request.URL.host isEqualToString:@"ready"])
  {
    _loaded = YES;

    [UIView animateWithDuration:0.1
                          delay:0
                        options:UIViewAnimationOptionAllowUserInteraction
                     animations:^{ webView.alpha = 1.0f; }
                     completion:nil];

    [self sizeToFit];
    return NO;
  }

  return YES;
}

@end

所以基本上这个 UIView 子类所做的就是嵌入一个不可见的 _webview。然后,当文档加载并呈现时,基于 jQuery 的 JavaScript 会尝试使用自定义 URL 方案离开当前页面。此导航被拒绝。但是作为响应,视图大小要适合并从 HTML 文档中获取正确的大小。

请注意,您不必使用 jQuery。您可以添加 DOM JavaScript 事件。我只是更熟悉 jQuery 如何处理原始 DOM 事件。

在您的情况下,您必须与滚动视图沟通内容已完成加载并且滚动视图视图应该重新布局。您可以使用委托协议或类似的东西来做到这一点。或者,滚动视图可能是“MyWebView”容器 UIView 子类。根据需要进行调整。

于 2013-05-03T02:32:34.037 回答
0

属性不会被重置,所以当你回到这个控制器时,你需要webViewCalculating = YES; 让它不会立即使 while 循环失败。

如果你已经这样做了,你可以尝试把

[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];

与在

-(void)webViewDidFinishLoad:(UIWebView *)webView
{

}

委托方法

希望这是有用的。

于 2013-05-02T13:44:57.910 回答