【问题标题】:Rendering PDF in UIWebView iOS 8, causes a black border around PDF在 UIWebView iOS 8 中渲染 PDF,导致 PDF 周围出现黑色边框
【发布时间】:2014-11-06 22:38:38
【问题描述】:

在 iOS 8 中,当将 .PDF 渲染为 UIWebview 时,显示的 PDF 周围会出现黑色边框和背景(不是整个背景视图)。请注意,这不是设置为的 UIWebview 背景:

myWebView.opaque = NO;
myWebView.backgroundColor = [UIColor clearColor];

这在

还有其他人经历过这种情况,可以对此有所了解吗?

我正在像这样将我的 PDF 加载到 Web 视图中......

- (void)viewWillAppear:(BOOL)animated
{

    [super viewWillAppear:animated];
    if (self.pdfData != nil && self.viewHasUnloaded == YES) {
        self.viewHasUnloaded = NO;
        [self.webView loadData:self.pdfData MIMEType:@"application/pdf" textEncodingName:@"utf-8" baseURL:nil];
    }
}

【问题讨论】:

  • iOS8.3 对我来说似乎不再发生这种情况

标签: ios objective-c uiwebview ios8


【解决方案1】:

经过一番调查后,我设法了解了问题所在。所以UIWebViewUIView,以UIScrollView(带有私有类_UIWebViewScrollView)作为子视图。将 PDF 加载到 UIWebView 遵循以下流程:
1) UIWebView 开始加载请求。此时,-webViewDidStartLoad: 委托方法已被调用。
2) PDF 被(下载)加载后,委托方法 -webViewDidFinishLoad: 被调用。到那时,UIWebView 知道这是一个 PDF 文件,并且具有私有类 UIWebPDFView 的子视图已插入到 _UIWebViewScrollView 中,但 PDF 本身尚未呈现。
问题来了。
3) PDF 在屏幕外渲染,准备好后,将私有类UIPDFPageView 的新子视图插入UIWebPDFView 并显示PDF。问题是当这种插入发生时,UIWebPDFViewbackgroundColor 设置为黑色,并且这种插入发生在调用-webViewDidFinishLoad: 之后(时间取决于要渲染的 PDF 的大小)。这就是为什么它不是一个很好的解决方案,例如遍历UIWebView 的所有子视图并将其backgroundColor 属性设置为白色。

好消息是UIViewController 的方法-viewDidLayoutSubviewsUIPDFPageView 插入UIWebView 的视图层次结构时被调用。所以,最终的解决方案是把这个 Objective-C 代码放到我们的视图控制器中:

-(void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    // Assuming self.webView is our UIWebView
    // We go though all sub views of the UIWebView and set their backgroundColor to white
    UIView *v = self.webView;
    while (v) {
        v.backgroundColor = [UIColor whiteColor];
        v = [v.subviews firstObject];
    }
}

在 Swift 中:

override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    var v:UIView? = self.webView
    while (v != nil) {
        v!.backgroundColor = UIColor.whiteColor()
        v = v!.subviews.first
    }
}

【讨论】:

  • 我仍然使用此解决方案在 PDF 中获得黑色背景,调用了 viewDidLayoutSubviews,但它没有区别吗?我试过把[v.subviews firstObject]改成[v.subviews lastObject],对我来说还是一样
  • 它在我的测试中工作正常。尝试 NSLog(@"%@", v);在 while 内,看看最后一次调用它是否会有UIPDFPageView
  • 不,PDF 周围和后面是纯黑色背景,您提到的边框和阴影被黑色背景隐藏。我想将不得不等待iOS8中的更新。感谢您的帮助,为您投票
  • 非常适合我!我在 iPad 应用程序的弹出式控制器中使用它。
  • 这对我有用 UIView *v = self.webView.scrollView; while (v) { v.backgroundColor = [UIColor whiteColor]; v = [v.subviews firstObject]; } *注意循环滚动视图子视图
【解决方案2】:

关闭WebKitDiskImageCacheEnabled,黑边消失:

在 applicationDidFinishLaunchingWithOptions 添加以下行:

[[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"WebKitDiskImageCacheEnabled"];
[[NSUserDefaults standardUserDefaults] synchronize];

【讨论】:

  • 简洁明了!
【解决方案3】:

我认为这有点时间问题,因为 UIWebPDFView 被添加为子视图,直到渲染完成并且在此之前调用 viewDidLayoutSubviews。因为没有像 didFinshedRendering 这样的事件,所以我使用了一个计时器来检查何时添加了UIWebPDFView

以下内容对我有用。

在头文件或你的类中放一个实例变量:

// instance variable for interval timer
NSTimer *BackgroundIntervalTimer;

将这些方法放在实现文件中:

- (void)startUIWebViewBackgroundFixTimer {
    // if > iOS 8 start fixing background color of UIWebPDFView
    if (!SYSTEM_VERSION_LESS_THAN(@"8.0")) {
        // hide pdfWebView until background fixed
        self.pdfWebView.alpha = 0.0;
        // start interval timer
        BackgroundIntervalTimer = [NSTimer scheduledTimerWithTimeInterval:0.1  target:self selector:@selector(fixBackground) userInfo:nil repeats:YES];
    }
}

- (void)stopUIWebViewBackgroundFixTimer {
    [BackgroundIntervalTimer invalidate];
    BackgroundIntervalTimer = nil;
}

- (void)fixBackground {
    // stop timer interval
    [self stopUIWebViewBackgroundFixTimer];

    // Assuming self.webView is our UIWebView
    // We go though all sub views of the UIWebView and set their backgroundColor to white
    UIView *v = self.pdfWebView;
    while (v) {
        //v.backgroundColor = [UIColor whiteColor];
        v = [v.subviews firstObject];

        if ([NSStringFromClass([v class]) isEqualToString:@"UIWebPDFView"]) {
            [v setBackgroundColor:[UIColor whiteColor]];

            // background set to white so fade view in and exit
            [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut
                             animations:^{
                                 self.pdfWebView.alpha = 1.0;
                             }
                             completion:nil];
            return;
        }
    }
    // UIWebPDFView doesnt exist yet so exit and try later
    [self startUIWebViewBackgroundFixTimer];
}

现在将此行放在加载 pdf 的行之后:

// if iOS 8 check if pdfWebView got subview of class UIWebPDFView
[self startUIWebViewBackgroundFixTimer];

提示:

  • SYSTEM_VERSION_LESS_THAN 是一个宏,用于确保代码仅在 iOS 8 及更高版本上执行。
  • self.pdfWebView 是你的 UIWebView。

【讨论】:

  • 更新,不知道是不是iOS V8.02的原因,这个解决方案现在不能一直工作了...回到绘图板!
  • 我在 iOS 8.0.2 发布时测试了代码,从那时起没有发现任何问题,代码按预期工作。将在 8.1 中再次检查,希望届时不再需要此修复。
  • 现在对我来说,第一次加载视图时它不起作用,然后在其他时间随机工作。我同意希望它会尽快修复
  • 尝试将修复添加到 webViewDidFinishLoad-Method 中:- (void)webViewDidFinishLoad:(UIWebView *)webView { // just in case... if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) { // hide pdfWebView until background fixed [self performSelector:@selector(fixBackground) withObject:nil afterDelay:0.5]; } }
【解决方案4】:

解决办法在这里:

编辑(链接断开)

How to remove black border from PDF/UIWebView in iOS 8

它对我有用。

诀窍是在 webView 加载完成后更改背景颜色。

编辑

在 iOS 8.0 中,如果您在 UIWebView 中加载 PDF 页面,那么您将 获取页面周围的黑色边框。

当您将 PDF 加载到 webview 时,它会将 UIWebPDFView 插入 网页视图。

当 PDF 被渲染时,它会添加一个新的私有类 UIPDFPageView 到 UIWebPDFView 具有黑色背景色。这一切插入 在调用 -webViewDidFinishLoad: 方法之后发生。所以你需要 设置后设置清晰或白色的背景颜色 -webViewDidFinishLoad:方法

添加以下方法去除黑色边框颜色

调用-webViewDidFinishLoad中的函数:

if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(@"8.0")) {
    [self performSelector:@selector(clearBackground) withObject:nil afterDelay:0.1];
}

.

- (void)clearBackground {
    UIView *v = webVw;
    while (v) {
        //v.backgroundColor = [UIColor whiteColor];
        v = [v.subviews firstObject];

        if ([NSStringFromClass([v class]) isEqualToString:@"UIWebPDFView"]) {
            [v setBackgroundColor:[UIColor whiteColor]];

            // background set to white so fade view in and exit
            [UIView animateWithDuration:0.25 delay:0.0 options:UIViewAnimationOptionCurveEaseOut
                             animations:^{
                                 webVw.alpha = 1.0;
                             }
                             completion:nil];
            return;
        }
    }
}

【讨论】:

  • Thnx,为我工作,我用 dispatch_after 替换了 performSelector 的东西,以尽可能减少这个丑陋的解决方案:-)
【解决方案5】:

对于任何使用 Xamarin 的人来说,gravers 解决方案的变体一旦转换为 C# 就可以工作。

在 UIViewController 中放置以下内容:

public override void ViewDidLayoutSubviews()
    {
        base.ViewDidLayoutSubviews();

        var subViews = webView.Subviews;
        foreach (UIView v in subViews) {
            v.BackgroundColor = UIColor.Clear;

            var subv = v.Subviews;
            foreach (UIView w in subv) {
                w.BackgroundColor = UIColor.Clear;

            }
        }
    }

【讨论】:

    【解决方案6】:

    我已经用 Swift 给出了答案。随意使用:

    override func viewDidLayoutSubviews() {
        var view :UIView?
        view = PdfView as UIView
        while (view != nil) {
            view?.backgroundColor = UIColor.clearColor()
            view = view?.subviews.first as? UIView
        }
    }
    

    PDFView 是我的 UIWebView 的名称。

    【讨论】:

      【解决方案7】:

      这是 railparade 在 Swift 中的实现:

      NSUserDefaults.standardUserDefaults().setObject(false, forKey: "WebKitDiskImageCacheEnabled")
      NSUserDefaults.standardUserDefaults().synchronize()
      

      【讨论】:

        【解决方案8】:

        我有同样的问题..无法使用建议的解决方案修复它我也尝试在 webViewDidFinishLoad 委托函数中设置背景颜色但没有用..

        NSLog 内容:

        -[TextualWebView webViewDidFinishLoad:](LNo.:141) PDF VIEW< UIWebView: 0x1c5ec6d0;  
        frame = (36 41; 637 810); opaque = NO; autoresize = W+H; layer = < CALayer: 0x1c5ec740>>
        
        -[TextualWebView webViewDidFinishLoad:](LNo.:141) PDF VIEW<_UIWebViewScrollView: 0x1c5f0070;  
         frame = (0 0; 637 810); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x1c5f02d0>;   
         layer = <CALayer: 0x1c5ef6f0>; contentOffset: {0, 0}; contentSize: {637, 810}>
        
        -[TextualWebView webViewDidFinishLoad:](LNo.:141) PDF VIEW< UIWebPDFView: 0x1c6e6320;  
         frame = (0 0; 637 810); opaque = NO; gestureRecognizers = <NSArray: 0x1c6e0330>;  
         layer = < CALayer: 0x1c6e6410>>
        

        【讨论】:

          【解决方案9】:

          这是Heikogravers 答案的混合。

          负责黑色背景的视图是 UIWebPDFView 的一个实例。所以我们可以使用 Gravers 的方法,但不会让每个 UIWebView 子视图都变白(这会弄乱页面指示器)。

          此外,此解决方案不对视图层次结构中的 UIWebPDFView 位置做出任何假设。

          - (void)viewDidLayoutSubviews
          {
              [super viewDidLayoutSubviews];
          
              [self fixWebviewBackground:self.webView];
          }
          
          - (void)fixWebviewBackground:(UIView *)view
          {
              if ([NSStringFromClass([view class]) isEqualToString:@"UIWebPDFView"]) {
                  view.backgroundColor = nil;
                  return;
              }
              for (UIView *subview in [view subviews]) {
                  [self fixWebviewBackground:subview];
              }
          }
          

          我们递归地遍历所有子视图,仅更改 UIWebPDFView 的背景颜色。

          【讨论】:

          • 这根本不适合我。两种方法都被调用,与最终结果没有区别
          • @JSA986 好吧,这取决于您何时将 PDF 数据加载到 UIWebView 中。您只需要在 UIWebView 第一次完成呈现 PDF 之后调用fixWebviewBackground:
          • 加载数据后添加代码 - 仍然没有
          【解决方案10】:

          我遇到了同样的问题,而且我试图在加载后放大我的 pdf。如果过早调用此代码,它将使 pdf 无法使用 - 您根本无法平移/滚动 pdf,您仍然可以捏拉缩放,但它只会放大到最左上角。

          我最初有一些代码可以在给定延迟后删除黑色边框并放大 pdf;

          - (void)webViewDidFinishLoad:(UIWebView *)webView {
              [self performSelector:@selector(zoomIntoPDF) withObject:nil afterDelay:0.6];
          }
          

          0.6s 的延迟是没用的。在(使用中的)iPhone 4S 上进行测试时(有时)仍然不够长。在最新的设备上,0.6 秒的性能提升在延迟


          @graver 的解决方案帮助我调查了这个问题。正如建议的那样,我在 while 循环中运行 NSLog(@"%@", v);(我也在 while 循环之前运行 NSLog(@"-------------");)。

          我也在像这样延迟 0.6 秒后打电话给viewDidLayoutSubviews

          [self performSelector:@selector(viewDidLayoutSubviews) withObject:nil afterDelay:0.6];
          

          这些是我的日志:

          -------------
          <UIWebView: 0x7fd803c2e920; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <CALayer: 0x7fd803c18290>>
          <_UIWebViewScrollView: 0x7fd803f6a720; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x7fd803f6afb0>; layer = <CALayer: 0x7fd803f6a660>; contentOffset: {0, 0}; contentSize: {320, 568}>
          <UIWebBrowserView: 0x7fd80487b400; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x7fd803f65290>; layer = <UIWebLayer: 0x7fd803da2050>>
          -------------
          <UIWebView: 0x7fd803c2e920; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <CALayer: 0x7fd803c18290>>
          <_UIWebViewScrollView: 0x7fd803f6a720; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x7fd803f6afb0>; layer = <CALayer: 0x7fd803f6a660>; contentOffset: {0, 0}; contentSize: {320, 568}>
          <UIWebBrowserView: 0x7fd80487b400; frame = (0 0; 320 568); opaque = NO; gestureRecognizers = <NSArray: 0x7fd803f65290>; layer = <UIWebLayer: 0x7fd803da2050>>
          Reachability Flag Status: -R -----l- networkStatusForFlags
          Reachability Flag Status: -R ------- networkStatusForFlags
          -------------
          <UIWebView: 0x7fd803c2e920; frame = (0 0; 320 568); opaque = NO; autoresize = W+H; layer = <CALayer: 0x7fd803c18290>>
          <_UIWebViewScrollView: 0x7fd803f6a720; frame = (0 0; 320 568); clipsToBounds = YES; autoresize = H; gestureRecognizers = <NSArray: 0x7fd803f6afb0>; layer = <CALayer: 0x7fd803f6a660>; contentOffset: {0, 0}; contentSize: {320, 273.14641744548288}>
          <UIWebPDFView: 0x7fd803c02570; frame = (0 0; 320 273.146); opaque = NO; gestureRecognizers = <NSArray: 0x7fd803c239d0>; layer = <CALayer: 0x7fd803c16a70>>
          <UIPDFPageView: 0x7fd80601cf60; frame = (0 7; 320 259); tag = 1000000; gestureRecognizers = <NSArray: 0x7fd803c27db0>; layer = <CALayer: 0x7fd803ddd2f0>>
          

          如您所见,UIPDFPageView 直到最后才出现 - 第三次也是最后一次 viewDidLayoutSubviews 被延迟调用。


          编辑:这与@Heiko 的答案非常相似,但使用的是递归方法而不是计时器。

          一定有更好的解决方案,比如检测webViews子视图的变化,但是这个解决方案目前有效:

          - (void)webViewDidFinishLoad:(UIWebView *)webView
          {
              [self.webView setScalesPageToFit:YES];
              loopCap = 0;
              [self performSelector:@selector(hasPDFLoaded) withObject:nil afterDelay:0.05];
          }
          
          - (void)hasPDFLoaded
          {
              BOOL containsPDF = NO;
              for (UIView *child in self.webView.scrollView.subviews)
              {
                  if ([NSStringFromClass([child class]) isEqualToString:@"UIWebPDFView"]) {
                      containsPDF = YES;
                  }
              }
              if (containsPDF) {
                  [self fixWebviewAndZoom];
              } else {
                  if (loopCap < 20) {
                      loopCap++;
                      [self performSelector:@selector(hasPDFLoaded) withObject:nil afterDelay:0.05];
                  }
              }
          }
          
          -(void)fixWebviewAndZoom {
              UIView *v = self.webView;
              while (v) {
                  v.backgroundColor = [UIColor whiteColor];
                  v = [v.subviews firstObject];
              }
              [self performSelector:@selector(zoomIntoPDF) withObject:nil afterDelay:0.05];
          }
          

          请原谅方法和变量名,明天我会想出更合适的!

          如您所见,它是一种递归方法,它会调用自身直到 pdf 加载完毕。有一个上限可以避免任何无限循环(如果此时没有加载,应该有一个警报或其他东西)。上限为 20,延迟为 0.05 秒,允许 1 秒加载 pdf。我可能会将上限增加到 40,但我认为 0.05 在性能方面还可以,但我需要进行一些适当的测试。

          我希望这很有见地,但我非常感谢对此解决方案的一些反馈或改进。

          【讨论】:

            【解决方案11】:

            最简单但不太理想的解决方法是在 UIWebView 周围添加与 pdf 文档背景颜色相同颜色的边框。这将在一定程度上防止丑陋,直到 Apple 解决问题。

            【讨论】:

              【解决方案12】:

              在 PDF 完成加载后更改 UIWebView 子视图的背景颜色——上面大多数答案的本质——对我有用。但是,我发现从 iOS 5 开始,webViewDidFinishLoad 在 web 视图实际完成加载之前被调用,所以我一直这样做是为了避免我的应用程序中出现各种问题:

              - (void)webViewDidFinishLoad:(UIWebView *)documentView {
                  [self performSelector:@selector(webViewDidReallyFinishLoad:) withObject:documentView afterDelay:0.5];
              }
              
              - (void)webViewDidReallyFinishLoad:(UIWebView *)documentView {
                  // now we can restore the transparency
              }
              

              webViewDidFinishLoad 的误导行为可能解释了为什么这种方法对某些人不起作用。

              此行为的另一个后果是 webView.scrollView.contentSize 在调用 webViewDidFinishLoad 时尚未设置。我在 2011 年 10 月将此作为错误 10259756 提交给 Apple,但他们以“行为正确”的状态关闭了错误报告。

              【讨论】:

                猜你喜欢
                • 2015-02-12
                • 1970-01-01
                • 1970-01-01
                • 2020-02-14
                • 2023-04-02
                • 2014-12-07
                • 1970-01-01
                • 2022-10-09
                • 1970-01-01
                相关资源
                最近更新 更多