it-swarm.com.de

Rendering PDF In UIWebView iOS 8 wird ein schwarzer Rand angezeigt PDF

In iOS 8 wird beim Rendern einer .PDF-Datei in eine UIWebview ein schwarzer Rahmen und ein Hintergrund um PDF angezeigt (nicht die gesamte Hintergrundansicht). Beachten Sie, dass dies nicht der UIWebview-Hintergrund ist, der auf Folgendes eingestellt ist:

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

Dies ist in <iOS8 nicht vorhanden (kein schwarzer Hintergrund mit farbigem Hintergrund um die .PDF-Datei)

Hat das noch jemand erlebt, der etwas Licht ins Dunkel bringen könnte?

Ich lade mein PDF gerne in die Webansicht.

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

Deaktivieren Sie WebKitDiskImageCacheEnabled. Der schwarze Rand wird entfernt:

Fügen Sie in applicationDidFinishLaunchingWithOptions die folgenden Zeilen hinzu:

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

Nachdem ich das Problem etwas untersucht hatte, konnte ich verstehen, wo das Problem liegt. Das UIWebView ist also ein UIView mit einem UIScrollView (mit der privaten Klasse _UIWebViewScrollView) als Unteransicht. Das Laden eines PDF in UIWebView geht in folgenden Ablauf:
1) UIWebView beginnt mit dem Laden der Anforderung. Zu diesem Zeitpunkt wird die -webViewDidStartLoad:-Delegat-Methode aufgerufen.
2) Nachdem das PDF (herunter) geladen wurde, wird die Delegatmethode -webViewDidFinishLoad: aufgerufen. Zu diesem Zeitpunkt weiß UIWebView, dass es sich um eine PDF Datei handelt, und eine Unteransicht mit der privaten Klasse UIWebPDFView ist bereits in _UIWebViewScrollView eingefügt, aber PDF selbst ist noch nicht gerendert.
Und hier kommt das Problem.
3) Das PDF wird außerhalb des Bildschirms gerendert und nach Fertigstellung wird eine neue Unteransicht mit der privaten Klasse UIPDFPageView in UIWebPDFView eingefügt und das PDF wird angezeigt. Das Problem ist, wenn diese Einfügung passiert, wenn UIWebPDFViewbackgroundColor auf Schwarz gesetzt ist und diese Einfügung erfolgt, nachdem der -webViewDidFinishLoad: aufgerufen wurde (die Zeit hängt davon ab, wie groß die PDF Datei ist). Aus diesem Grund ist es nicht eine gute Lösung, um alle Unteransichten von UIWebView durchzugehen und beispielsweise ihre backgroundColor-Eigenschaft auf Weiß zu setzen.

Die gute Nachricht ist, dass die Methode UIViewController-viewDidLayoutSubviews aufgerufen wird, wenn UIPDFPageView in die Ansichtshierarchie von UIWebView eingefügt wird. Am Ende besteht die Lösung darin, diesen Objective-C-Code in unseren View-Controller aufzunehmen:

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

Und in Swift:

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

Ich nehme an, es ist ein bisschen ein Timing-Ding, weil UIWebPDFView als Unteransicht erst dann hinzugefügt wird, wenn das Rendern beendet ist und viewDidLayoutSubviews aufgerufen wird, bevor dies geschieht. Und da es kein Ereignis wie didFinshedRendering gibt, habe ich mit einem Timer geprüft, wann UIWebPDFView hinzugefügt wird.

Folgendes arbeitet für mich.

Fügen Sie eine Instanzvariable in der Header-Datei oder Ihrer Klasse ein:

// instance variable for interval timer
NSTimer *BackgroundIntervalTimer;

Fügen Sie diese Methoden in die Implementierungsdatei ein:

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

Fügen Sie nun diese Zeile direkt hinter der Zeile ein, in die Sie das PDF laden:

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

Hinweise:

  • SYSTEM_VERSION_LESS_THAN ist ein Makro, um sicherzustellen, dass der Code nur unter iOS 8 und höher ausgeführt wird.
  • self.pdfWebView ist Ihre UIWebView.
9
Heiko

Die Lösung ist hier:

EDIT (Link defekt)

 So entfernen Sie den schwarzen Rand von PDF/UIWebView in iOS 8

Es hat für mich funktioniert.

Der Trick besteht darin, die Hintergrundfarbe nach dem Laden von webView zu ändern.

EDIT

Wenn Sie in iOS 8.0 eine PDF - Seite in UIWebView laden, werden Sie Holen Sie sich den schwarzen Rand um die Seite.

Wenn Sie PDF in Webview laden, fügen Sie UIWebPDFView in .__ ein. Webview.

Wenn PDF gerendert wird, fügen Sie eine neue private Klasse UIPDFPageView in .__ hinzu. UIWebPDFView, die eine schwarze Hintergrundfarbe haben. Dies alles Einfügung geschieht nach dem Aufruf der -webViewDidFinishLoad: -Methode. Deswegen brauchst du um eine klare oder weiße Hintergrundfarbe nach dem .__ einzustellen. -webViewDidFinishLoad: Methode

Fügen Sie die folgende Methode hinzu, um die schwarze Rahmenfarbe zu entfernen

Rufen Sie die Funktion in -webViewDidFinishLoad auf:

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

Dies ist die Implementierung von railparade in Swift:

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

Ich habe die Antwort in Swift gemacht. Fühlen Sie sich frei zu verwenden:

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

PDFView ist der Name meiner UIWebView.

2
LiveNL

Für jeden, der Xamarin einsetzte, funktionierte eine Variationsvariante von Gravern, sobald er in C # übersetzt wurde.

Fügen Sie Folgendes in den UIViewController ein:

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;

            }
        }
    }
2

Ich habe das gleiche Problem .. Kann das Problem mit der vorgeschlagenen Lösung nicht beheben. Ich habe auch versucht, die Hintergrundfarbe in der WebViewDidFinishLoad-Delegatenfunktion festzulegen, aber ohne Verwendung.

NSLog-Inhalt: 

-[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>>
0
CallMeSan

Das Ändern der Hintergrundfarbe der Unteransichten des UIWebView, nachdem das Laden von PDF abgeschlossen ist - die Essenz der meisten der obigen Antworten - funktioniert für mich. Ich habe jedoch festgestellt, dass seit iOS 5 webViewDidFinishLoad aufgerufen wird, bevor die Webansicht tatsächlich geladen wird. Daher habe ich dies getan, um verschiedene Probleme in meinen Apps zu vermeiden:

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

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

Das irreführende Verhalten von webViewDidFinishLoad kann erklären, warum dieser Ansatz bei manchen Leuten nicht funktioniert.

Eine weitere Konsequenz dieses Verhaltens ist, dass webView.scrollView.contentSize noch nicht festgelegt ist, wenn webViewDidFinishLoad aufgerufen wird. Ich habe dies im Oktober 2011 als Fehler 10259756 an Apple übermittelt, aber der Fehlerbericht wurde mit dem Status "Behavior korrekt" geschlossen.

0
arlomedia

Dies ist eine Mischung aus Heiko und Gravers Antworten.

Die für den schwarzen Hintergrund verantwortliche Ansicht ist eine Instanz von UIWebPDFView. Wir können also den Ansatz der Gravierer verwenden, ohne jedoch jede UIWebView-Unteransicht weiß zu machen (was den Seitenanzeiger durcheinander bringt).

Diese Lösung macht auch keine Annahme über die UIWebPDFView-Position in der Ansichtshierarchie.

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

Wir rekursiv von allen Unteransichten ab und ändern nur die backgroundColor der UIWebPDFView.

0
Guillaume Algis

Ich hatte genau das gleiche Problem, und ich habe versucht, mein PDF zu vergrößern, nachdem es geladen wurde. Wenn dieser Code vorzeitig aufgerufen wurde, würde er die PDF-Datei unbrauchbar machen - Sie konnten die PDF-Datei überhaupt nicht schwenken/scrollen, Sie könnten zwar immer noch zoomen, sie zoomten jedoch nur in die linke obere Ecke.

Ich hatte anfangs etwas Code, um den schwarzen Rand zu entfernen und nach einer bestimmten Verzögerung in das PDF zu zoomen.

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

Die Verzögerung von 0,6 Sekunden ist jedoch nutzlos. Es würde (manchmal) immer noch nicht lang genug sein, wenn auf einem (in Verwendung befindlichen) iPhone 4S getestet wird. Bei den neuesten Geräten ist ein Leistungsabfall von 0,6s lächerlich, wenn er mit einer Verzögerung von <0,05s arbeitet.


Die Lösung von @graver half mir, das Problem zu untersuchen. Wie vorgeschlagen, habe ich NSLog(@"%@", v); in der while-Schleife ausgeführt (ich habe auch NSLog(@"-------------"); vor der while-Schleife ausgeführt).

Ich rief auch viewDidLayoutSubviews nach einer Verzögerung von 0,6s an;

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

Dies sind meine Protokolle:

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

Wie Sie sehen, erscheint UIPDFPageView erst am Ende - das dritte und letzte Mal, dass viewDidLayoutSubviews von der Verzögerung aufgerufen wurde.


EDIT: Dies ist ein sehr ähnliches Prinzip wie bei @ Heiko, verwendet jedoch eine rekursive Methode anstelle eines Timers.

Es muss eine bessere Lösung geben, z. B. das Erkennen einer Änderung in den webViews-Unteransichten. Diese Lösung funktioniert jedoch vorerst:

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

Bitte entschuldigen Sie die Methoden- und Variablennamen, ich werde mir morgen passende aussuchen!

Wie Sie sehen, handelt es sich um eine rekursive Methode, die sich selbst aufruft, bis das PDF geladen ist. Es gibt eine Kappe, um unendliche Schleifen zu vermeiden (es sollte eine Warnung geben oder etwas, wenn es in dieser Zeit nicht geladen wurde). Die Obergrenze beträgt 20 und die Verzögerung beträgt 0,05 Sekunden, sodass das PDF 1 Sekunde lang geladen werden kann. Ich werde die Obergrenze wahrscheinlich auf 40 erhöhen, aber ich denke, 0,05 ist in Bezug auf die Leistung in Ordnung, aber ich muss einige Tests durchführen.

Ich hoffe, dass dies aufschlussreich war, aber ich würde mich über Feedback oder Verbesserungen dieser Lösung sehr freuen.

0
Patrick

Die einfachste, aber nicht so ideale Lösung ist das Hinzufügen eines Rahmens um die UIWebView in derselben Farbe wie die Hintergrundfarbe Ihres PDF-Dokuments. Dies wird die Hässlichkeit bis zu einem gewissen Grad verhindern, bis Apple das Problem behoben hat.

0
Kumar Summan