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.
Use printPageRenderer
property of your UIPrintIterationController object. You can set multiple UIPrintFormatter subclasses in a UIPrintPageRenderer subclass object.
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:
- 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.
- Add the printFormatters via:
[addPrintFormatter:startingAtPageAtIndex:]
- 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 ;)