Using One or More Formatters with a Page Renderer

2019-05-21 08:49发布

问题:

Has anyone tried using multiple formatters (UIViewPrintFormatter, UIMarkupTextPrintFormatter, UISimpleTextPrintFormatter) with a page renderer (UIPrintPageRenderer) to print the content?

I'm trying to use two UIMarkupTextPrintFormatters with a UIPrintPageRenderer subclass, but i'm failing to get the print. I'm using MyPrintPageRenderer class from PrintWebView sample code.

I've gone through the Apple's documentation but it isn't very helpful, and there is no sample code associated with the description. I've tried a couple of solutions but so far I haven't had any success.

Any suggestions?

回答1:

The fact that there is very little activity in the "Printing" section suggests that either not many people are using this, or people using this API are not visiting this community, or people are just ignoring the question for some reason.

Anyways, i was able to solve my problem. I was using setPrintFormatters: method earlier which wasn't/isn't working. I don't know why. So, i started experimenting with addPrintFormatter:startingAtPageAtIndex: method instead. And here's how i solved my problem:

// To draw the content of each page, a UIMarkupTextPrintFormatter is used.
NSString *htmlString = [self prepareWebViewHTML];
UIMarkupTextPrintFormatter *htmlFormatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:htmlString];

NSString *listHtmlString = [self prepareWebViewListHTMLWithCSS];
UIMarkupTextPrintFormatter *listHtmlFormatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:listHtmlString];

// I think this should work, but it doesn't! The result is an empty page with just the header and footer text.
// [myRenderer setPrintFormatters:[NSArray arrayWithObjects:htmlFormatter, listHtmlFormatter, nil]];

// Alternatively, i've used addPrintFormatters here, and they just work!
// Note: See MyPrintPageRenderer's numberOfPages method implementation for relavent details.
// The important point to note there is that the startPage property is updated/corrected.
[myRenderer addPrintFormatter:htmlFormatter startingAtPageAtIndex:0];
[myRenderer addPrintFormatter:listHtmlFormatter startingAtPageAtIndex:1];

In the MyPrintPageRenderer, i used following code to update/correct the startPage property so that a new page is used for each formatter:

- (NSInteger)numberOfPages
{
    // TODO: Perform header footer calculations
    // . . .

    NSUInteger startPage = 0;
    for (id f in self.printFormatters) {
        UIPrintFormatter *myFormatter = (UIPrintFormatter *)f;

        // Top inset is only used if we want a different inset for the first page and we don't.
        // The bottom inset is never used by a viewFormatter.
        myFormatter.contentInsets = UIEdgeInsetsMake(0, leftInset, 0, rightInset);

        // Just to be sure, never allow the content to go past our minimum margins for the content area.
        myFormatter.maximumContentWidth = self.paperRect.size.width - 2*MIN_MARGIN;
        myFormatter.maximumContentHeight = self.paperRect.size.height - 2*MIN_MARGIN;

        myFormatter.startPage = startPage;
        startPage = myFormatter.startPage + myFormatter.pageCount;
    }

    // Let the superclass calculate the total number of pages
    return [super numberOfPages];
}

I still don't know if there is anyway to APPEND the printable content of both htmlFormatter and listHtmlFormatter (using this approach). e.g. rather than using a new page for listHtmlFormatter, continue printing from where htmlFormatter ended.



回答2:

I'm adding this extra info answer here because I spent 2 days dk'n around with this and Mustafa's answer saved me. Hopefully all this in one place will save others a lot of wasted time.

I was trying to figure out why I was unable get my custom UIPrintPageRenderer to iterate over an array of viewPrintFormatter from several UIWebViews that I need to print in ONE job, and have it properly calculate pageCount as these Apple docs suggest it should: PrintWebView

The key was to add them via this method:

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

and NOT this one:

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

The Apple docs suggest that the UIPrintPageRenderer gets page count from the print formatters in the array as long as the proper metrics are set on the print formatters, as Mustafa shows above. But it only works if you add them via addPrintFormatter:startingAtPageAtIndex:

If you add them as an array, the printFormatters (regardless of what metrics you set on them) will return a page count of 0!

One additional note for people using this approach, put the update to viewPrintFormatter.startPage in a dispatch_async block, else you'll get an exception:

dispatch_async(dispatch_get_main_queue(), ^{
    myFormatter.startPage = startPage;
    startPage = myFormatter.startPage + myFormatter.pageCount;
});


回答3:

To add to @Mustafa's answer, startPage needs to be declared as:

__block NSUInteger startPage

if it's to be used inside the dispatch_async block