打印UIWebView时出现意外的分页

14

TLDR:如果您打印包含使用right/center文本对齐的HTML元素内容的UIWebView,生成的文档将具有意外大的底部边距。

我发现这个问题时很惊讶,因为搜索不到有类似问题的人。 我向苹果提交了一个雷达(#20760071),并在ResearchKit的GitHub存储库上创建了一个问题,因为这会影响到他们的ORKHTMLPDFWriter

据我所知,这也会影响所有使用UIWebViewHTML转换为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>

然而,上述方法均无法对齐变长文本,而我关注的主要用例就是这种情况。


我在2014年4月24日提交了rdar://16713582关于同样的问题。正如你所提到的,当使用文档CSS中的text-align时,问题似乎会发生。我能想到的唯一解决方案是避免使用text-align,而是使用其他方法。例如,您可以使用margin-left:auto; margin-right:0;将一个div右对齐到另一个div中。 - Dalzhim
@Dalzhim,你提到的解决方法只适用于指定对齐div的宽度,这通常不适用于文本对齐。或者我有什么遗漏吗? - Jakub Vano
我不记得每个解决方法的具体细节,但有各种方法可以重现文本对齐,但由于它们的缺点,并不适用于每种情况。例如,float:right;技术会导致不同的布局,这并不总是合适的。正如我所说,我没有完整的解决方案,只有这个有限的解决方法来避免打印问题。当然,您也可以仅在媒体打印时使用打印解决方法,以尽可能地减少副作用。 - Dalzhim
3个回答

4

Vano,

经过一些测试,我想到的解决方案是添加以下带有文本对齐的CSS规则。

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

0

文本靠右的解决方案

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

-1

我想象这个方法无法对齐变长文本,因为文本的长度显然是不断变化的,而你的解决方法中 div 属性有一个静态的 width 属性。

这需要进行字符串替换,将分隔符的 width 替换为纸张的大小(以便边距填充文本)。要获取此宽度,请调用以下内容:

pc.printPaper.printRect.size.width;

但是,为了替换它,你需要有一个委托在工作开始之前修复HTML代码。

让你的委托成为Xcode文件创建器中类型为NSObject的新类对象的子类,然后让你的函数触发打印机并渲染内容,在你的视图中类似于这样:

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设置为打印区域的宽度。唯一的其他选项是要么有指定的宽度(就像您在编辑中建议的那样),要么有一个特定类型的纸张供用户打印。

发生这种情况的原因是由于打印UIWebView的HTML时出现了错误,而不是由于编码问题。希望苹果在以后的更新中修复这个问题。


您已经描述了如何将分隔线的宽度设置为纸张的宽度。好吧,style="width:100%"可以实现相同的结果,我看不出这与问题有任何关系。 - Jakub Vano

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接