Using One or More Formatters with a Page Renderer in iOS

♀尐吖头ヾ 提交于 2019-12-06 13:39:39

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.

Cliff Ribaudo

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;
});

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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!