Неожиданные разрывы страниц при печати UIWebView

TLDR: если вы печатаете UIWebView который содержит HTML содержимое, состоящее из элементов с выравниванием текста right / center, получившийся документ будет иметь страницы с неожиданно большими нижними полями.

Я столкнулся с этой проблемой, и был довольно удивлен, когда я не мог гуглить никого с подобной проблемой. Я подал радар с яблоком (#20760071), а также создал проблему на ResearchKit GitHub РЕПО, как это влияет на их ORKHTMLPDFWriter,

AFAIK это также влияет на все библиотеки, которые используют UIWebView для конвертации HTML в PDF Я проверил:

Мне интересно, если кто-нибудь может придумать какое-то решение.

Как воспроизвести:

NSMutableString* html = [NSMutableString string];
[html appendString:@"<html><body>"];
for (int i=0; i<200; i++) {
    [html appendString:@"<div align=\"right\">line</div>"];
}
[html appendString:@"</body></html>"];

UIPrintInteractionController* pc = [UIPrintInteractionController sharedPrintController];

UIPrintInfo* printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGrayscale;

pc.printInfo = printInfo;
pc.showsPaperSelectionForLoadedPapers = YES;

UIWebView* web = [UIWebView new];
[web loadHTMLString:html baseURL:nil];
pc.printFormatter = web.viewPrintFormatter;

[pc presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
    NSLog(@"%d -- %@",completed, error);

}];

Вы также можете клонировать проект, демонстрирующий эту проблему в ResearchKit,


Изменить - несколько полезных обходных путей:

Зная конкретную ширину контента (например, изображений), можно выровнять его без указания выравнивания текста, например:

Использование автоматических полей:

<div>
    <div style="width:200px; margin-left:auto; margin-right:0px;">
        content
    </div>
</div>

Плавающие колонны:

<div>
    <div style="width:200px; float:right;">
        content
    </div>
</div>

Тем не менее, ни один из вышеперечисленных не работает для выравнивания текста переменной длины, что является основным вариантом использования, который меня интересует.

3 ответа

Решение

Вано,

Решение, которое я нашел после некоторого тестирования, заключается в добавлении следующих правил CSS с выравниванием текста.

display: -webkit-box;
display: -webkit-flex;
display: flex;
justify-content: flex-end;
-webkit-justify-content: flex-end;
text-align:right;

Мое решение для выравнивания текста: право

<header>
    <style type="text/css">
        .default-text-align-right {
            text-align: right;
        }
        .alternative-text-align-right {
            position: absolute;
            right: 10px;
        }
    </style> 
</header>
<body>
    <div>
        <div class="default-text-align-right">
            Default Text Align Left
        </div>
        <div>
            <div class="alternative-text-align-right">Alternative Text Align Right</div>
            <div>&nbsp;</div>
        </div>
        <div class="default-text-align-right">
            Default Text Align Left
        </div>  
    </div>      
</body>

Я полагаю, что это не будет работать с выравниванием текста переменной длины, потому что длина текста, очевидно, постоянно меняется, где ваш обходной путь div атрибут имеет статический width приписывать.

Это работа для замены строки, замены делителя width с размером бумаги (чтобы поля могли заполняться текстом). Чтобы получить эту ширину, назовите это:

pc.printPaper.printRect.size.width;

Но для того, чтобы заменить его, вам нужен делегат, чтобы исправить код HTML прямо перед началом работы.

Пусть ваш делегат будет новым объектом класса из типа NSObject как подкласс в Создателе Файла XCode, и затем имейте свою функцию, чтобы запустить принтер и сделать содержание похожим на это в вашем представлении:

NSMutableString* html = [NSMutableString string];
[html appendString:@"<html><body>"];

for (int i=0; i<200; i++) {
    [html appendString:@"temporary content... "];
}

[html appendString:@"</body></html>"];

UIWebView* web = [UIWebView new];
[web loadHTMLString:html baseURL:nil];


UIPrintInteractionController* pc = [UIPrintInteractionController sharedPrintController];
pc.printFormatter = web.viewPrintFormatter;

UIPrintInfo* printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGrayscale;

printerDelegate* pd = [printerDelegate new];

pc.printInfo = printInfo;
pc.showsPaperSelectionForLoadedPapers = YES;
pc.delegate = pd;

[pc presentAnimated:YES completionHandler:^(UIPrintInteractionController *printInteractionController, BOOL completed, NSError *error) {
    NSLog(@"%d -- %@",completed, error);
}];

(Примечание: я сделал временный контент в файле HTML по причине. Я еще не сделал!)

В классе делегатов, который я просил вас сделать раньше, сделайте это .hфайл:

    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>

    @interface printerDelegate : NSObject <UIPrintInteractionControllerDelegate>

    @end

Тогда в это .m файл, у меня есть это...

#import "printerDelegate.h"
#import <UIKit/UIKit.h>

@implementation printerDelegate

-(void)printInteractionControllerWillDismissPrinterOptions:(UIPrintInteractionController *)printInteractionController {

    @try {
        NSMutableString* html = [NSMutableString string];
    [html appendString:@"<html><body>"];
    for (int i=0; i<200; i++) {
        [html appendString:[NSString stringWithFormat:@"<div><div style=""width:%fpx; margin-left:auto; margin-right:0px;"">content</div></div>", printInteractionController.printPaper.printRect.size.width]];
    }
    [html appendString:@"</body></html>"];
    UIWebView* web = [UIWebView new];
    [web loadHTMLString:html baseURL:nil];
    printInteractionController.printFormatter = web.viewPrintFormatter;
    }
    @catch (NSException *exception) {
        NSLog(@"%@", exception.debugDescription);
    }
    @finally {

    }
}

@end

Он возвращает исключение неверного доступа, но вы получаете суть: после того, как пользователь выберет свой тип бумаги, установите разделитель width быть шириной области печати. Единственный другой вариант - либо иметь указанную ширину (как вы предлагали при редактировании), либо использовать бумагу определенного типа, с которой пользователь может печатать.

Причина, по которой это происходит, заключается в ошибке при печати HTML-кода UIWebViewне из-за кодирования. Надеюсь, Apple исправит это в более позднем обновлении.

Другие вопросы по тегам