Printing Contents of Multiple UIWebViews in one go

2019-02-27 15:57发布

问题:

I have an iPad application that uses WebViews to display a list of URL's. I would like to be able to print all of the WebViews in one go, without prompting the user multiple times with the PrintInteractionController. The problem is that the PrintInteractionController does not appear to have the ability to do this. You cannot assign multiple viewFormatters, and the WebViews are not recognized as printItems. There is also no method that I can find to just print the items and not show the PrintInteractionController.

Does anyone know of a way to do this?

Cheers.

回答1:

Use printPageRenderer property of your UIPrintIterationController object. You can set multiple UIPrintFormatter subclasses in a UIPrintPageRenderer subclass object.



回答2:

This is an old question, but I spent several days searching for an answer and following some misleading comments in the Apple docs and sample code. So, I'm sticking this here to save the next guy the days I wasted.

The specific problem is: How does one write a UIPrintPageRenderer that can print multiple UIWebViews in a single print job given to a UIPrintInteractionController?

You can get pretty far along to a solution that doesn't involve converting everything to PDFs first using this Apple sample code: PrintWebView. Also this documentation will help some: UIPrintPageRenderer. The problem is that the sample App and the documentation for UPPrintPageRenderer suggest that if you add multiple UIPrintFormatter via this property:

@property(nonatomic,copy) NSArray <UIPrintFormatter *> *printFormatters

The sample code Apple provided for the method to override -(NSInteger)numberOfPages in PrintWebView will just work and figure out the correct page counts.... Nope!

What you have to do is add the printFormatters in a non-obvious way via the method shown below, and then correct their respective startPage properties and use these collectively to work out the correct pageCount for UIPrintPageRenderer to return. Instead, use this:

-(void)addPrintFormatter:(UIPrintFormatter *)formatter startingAtPageAtIndex:(NSInteger)pageIndex

Why does this works and the other doesn't? No idea, probably a bug.... I should file a radar :) But Thanks to @Mustafa and this other Stackoverflow answer for the hint:

Here are the steps to follow to print multiple UIWebViews in one print job:

  1. Follow the Apple outline in the PrintWebView example referenced above and write your UIPrintPageRenderer to set the properties you want on the webView.viewPrintFormatters you give to it.
  2. Add the printFormatters via: [addPrintFormatter:startingAtPageAtIndex:]
  3. In your UIPrintPageRenderer -(NSInteger)numberOfPages method get the pageCount from each formatter, and use that to update the startPage and total page count values.

Here is the basic code outline to follow (FYI: this solution is working for an App built with a deployment target of iOS 9.0):

Define your UIPrintPageRenderer class like so (you don't really need the init method, but in my use case I set values in there I always want that way):

@interface MyPrintPageRenderer : UIPrintPageRenderer
@end

@implementation MyPrintPageRenderer
-(id)init
{
    self = [super init];
    if(self) {
        self.headerHeight = 0;
        self.footerHeight = 0;
    }
    return self;
}

// 
// Set whatever header, footer and insets you want. It is
// important to set these values to something, so that the print
// formatters can figure out their own pageCounts for whatever
// they contain. Look at the Apple sample App for PrintWebView for
// for more details about these values.
//
-(NSInteger)numberOfPages
{
    __block NSUInteger startPage = 0;
    for(UIPrintFormatter *pf in self.printFormatters) {
        pf.contentInsets = UIEdgeInsetsZero;
        pf.maximumContentWidth = self.printableRect.size.width;
        pf.maximumContentHeight = self.printableRect.size.height;

        dispatch_async(dispatch_get_main_queue(), ^{
            pf.startPage = startPage;
            startPage = pf.startPage + pf.pageCount;
        });
    }
    return [super numberOfPages];
}
@end

In the Controller that handles the print action for the UIWebViews you want to print, do something like this:

-(void)printWebViews
{
    MyPrintPageRenderer *pr = [MyPrintPageRenderer new];
    //
    // Add the printFormatters at sequential startingPageIndexes,
    // your renderer will set them to the correct values later based
    // on the various page metrics and their content.
    //
    [pr addPrintFormatter:_webView1.viewPrintFormatter startingAtPageAtIndex:0];
    [pr addPrintFormatter:_webView2.viewPrintFormatter startingAtPageAtIndex:1];      
    [pr addPrintFormatter:_webView3.viewPrintFormatter startingAtPageAtIndex:2];

    // Set whatever values needed for these as per Apple docs
    UIPrintInfo *pi = [UIPrintInfo printInfo];
    pi.outputType = UIPrintInfoOutputGeneral;

    UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
    pic.printInfo = pi;
    pic.printPageRenderer = pr;
    [pic presentAnimated:NO completionHandler:nil];
}

And voila! Now... it just works ;)