Подтвердить что ты не робот

Рендеринг PDF в UIWebView iOS 8, вызывает черную рамку вокруг PDF

В iOS 8 при рендеринге .PDF в UIWebview есть черная рамка и фон вокруг отображаемого PDF (не весь фоновый вид). Обратите внимание, что это не фон UIWebview, который установлен на:

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

Это отсутствует в < iOS8 (нет черного граничащего цветного фона вокруг .PDF)

Кто-нибудь испытал это, кто мог пролить свет на это?

Я загружаю свой PDF файл в веб-представление так.

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

Ответ 1

Отключите WebKitDiskImageCacheEnabled, а черная рамка исчезнет:

В applicationDidFinishLaunchingWithOptions добавьте следующие строки:

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

Ответ 2

После небольшого изучения проблемы мне удалось понять, в чем проблема. Таким образом, UIWebView является UIView, с UIScrollView (с частным классом _UIWebViewScrollView) в качестве подсмотра. Загрузка PDF в UIWebView происходит в следующем потоке:
1) UIWebView начинает загрузку запроса. К этому времени вызывается метод делегата -webViewDidStartLoad:.
2) После загрузки PDF (вниз) вызывается метод делегата -webViewDidFinishLoad:. К тому времени UIWebView знает, что это файл в формате PDF, а subview с частным классом UIWebPDFView уже вставлен в _UIWebViewScrollView, но сам PDF не отображается.
И здесь возникает проблема.
3). PDF файл отображается на экране и после его завершения добавляется новое подвью с закрытым классом UIPDFPageView в UIWebPDFView и отображается PDF файл. Проблема в том, что когда эта вставка происходит, UIWebPDFView имеет свой backgroundColor, установленный в черный, и эта вставка происходит после вызова -webViewDidFinishLoad: (время зависит от того, насколько большой PDF файл рендеринга). Вот почему это не хорошее решение для просмотра всех подтекстов UIWebView и, например, установить их свойство backgroundColor на белый.

Хорошей новостью является то, что метод UIViewController -viewDidLayoutSubviews вызывается, когда UIPDFPageView вставляется в иерархию представлений 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
    }
}

Ответ 3

Я предполагаю, что это немного времени, потому что UIWebPDFView добавляется как subview только до завершения рендеринга и 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.

Ответ 4

Решение находится здесь:

EDIT (ссылка Broken)

Как удалить черную границу из PDF/UIWebView в iOS 8

Это сработало для меня.

Фокус в том, чтобы изменить цвет фона после загрузки веб-страницы.

ИЗМЕНИТЬ

В iOS 8.0, если вы загружаете страницу PDF в UIWebView, вы будете получить черную рамку вокруг страницы.

Когда вы загружаете PDF в веб-просмотр, он вставляет UIWebPDFView в WebView.

При рендеринге 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;
        }
    }
}

Ответ 5

Для тех, кто использует Xamarin, вариант решения граверов работал после перевода на С#.

Поместите в 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

Я сделал ответ в Свифт. Не стесняйтесь использовать:

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

Это реализация железной дороги в Swift:

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

Ответ 8

У меня такая же проблема. Невозможно исправить ее с помощью предлагаемого решения. Я также попробовал установить задний цвет фона в fufntion делегата 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

Это сочетание ответов Heiko и gravers.

Вид, отвечающий за черный фон, является экземпляром UIWebPDFView. Таким образом, мы можем использовать подход граверов, но не заставляя каждый подвектор 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.

Ответ 10

У меня была такая же проблема, плюс я пытался увеличить размер моего PDF файла после его загрузки. Если этот код был вызван преждевременно, это сделало бы файл pdf непригодным для использования - вы вообще не могли бы панорамировать/прокручивать PDF, вы все равно могли бы увеличить масштаб, но он увеличивался только в самом верхнем левом углу.

Вначале у меня был некоторый код для удаления черной границы и масштабирования в pdf после такой задержки, например:

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

Задержка 0,6 с бесполезна. Это было бы (иногда) еще не достаточно долго, когда тестирование на (в использовании) iPhone 4S. На последних устройствах производительность 0,6 с в производительности нелепо, когда она работала с задержкой < 0,05 с.


Решение

@graver помогло мне разобраться с проблемой. Как я предположил, я запускал NSLog(@"%@", v); в цикле while (я также выполнял NSLog(@"-------------"); перед циклом while).

Я также вызывал viewDidLayoutSubviews после задержки 0,6 с, например:

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


EDIT: Это очень похожий принцип ответа @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 нормально работает, но мне нужно провести надлежащее тестирование.

Я надеюсь, что это было проницательно, но я бы очень признателен за некоторые отзывы или улучшения этого решения.

Ответ 11

Простейшим, но не идеальным решением является добавление границы вокруг UIWebView того же цвета, что и цвет фона в pdf-документе. Это предотвратит уродство до некоторой степени, пока Apple не решит проблему.

Ответ 12

Изменение фонового цвета подзонов UIWebView после завершения загрузки PDF файла - суть большинства ответов выше - работает для меня. Тем не менее, я обнаружил, что с момента выхода iOS 5 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 может объяснить, почему этот подход не работает для некоторых людей.

Другим следствием этого поведения является то, что webView.scrollView.contentSize еще не установлен при вызове webViewDidFinishLoad. Я отправил это Apple в качестве ошибки 10259756 в октябре 2011 года, но они закрыли отчет об ошибке со статусом "Ведет себя правильно".