在UIWebView iOS 8中渲染PDF会导致PDF周围出现黑色边框

时间:2014-09-12 17:18:33

标签: ios objective-c uiwebview ios8

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

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

<< iOS8,(.PDF周围没有黑色边框彩色背景)

其他有经验的人可以对此有所了解吗?

我将我的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];
    }
}

12 个答案:

答案 0 :(得分:35)

经过一番调查后,我设法了解问题所在。因此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的视图层次结构中插入时被调用。因此,最终解决方案是将此Objective-C代码放入我们的视图控制器中:

UIWebView

在斯威夫特:

-(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];
    }
}

答案 1 :(得分:19)

关闭WebKitDiskImageCacheEnabled,黑色边框消失:

在applicationDidFinishLaunchingWithOptions中添加以下行:

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

答案 2 :(得分:9)

我认为这是一个时间性因素,因为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。

答案 3 :(得分:6)

解决方案在这里:

编辑(链接已损坏)

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;
        }
    }
}

答案 4 :(得分:2)

对于任何使用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;

            }
        }
    }

答案 5 :(得分:2)

我在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的名称。

答案 6 :(得分:2)

这是铁路手段在Swift中的实施:

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

答案 7 :(得分:0)

我有同样的问题..无法使用建议的解决方案修复它我也尝试在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>>

答案 8 :(得分:0)

这是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的backgroundColor。

答案 9 :(得分:0)

我有同样的问题,加上我试图在加载后放大我的PDF文件。如果过早调用此代码会导致pdf无法使用 - 您根本无法平移/滚动pdf,您仍然可以缩放到缩放,但它只会缩放到左上角。

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

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

0.6秒延迟无用。在(使用中)iPhone 4S上进行测试时,它(有时)仍然不够长。在最新的设备上,当它以<0.05s延迟工作时,性能下降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秒,允许加载pdf 1秒。我可能会将上限增加到40,但我认为0.05表现不错,但我需要进行一些适当的测试。

我希望这很有见地,但我真的很感激这个解决方案的一些反馈或改进。

答案 10 :(得分:0)

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

答案 11 :(得分:0)

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

- (void)webViewDidFinishLoad:(UIWebView *)documentView {
    [self performSelector:@selector(webViewDidReallyFinishLoad:) withObject:documentView afterDelay:0.5];
}

- (void)webViewDidReallyFinishLoad:(UIWebView *)documentView {
    // now we can restore the transparency
}

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

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