Как AirPrint несколько печатающих форматировщиков за один раз?

Моя конечная цель - создать несколько UIMarkupTextPrintFormatter и распечатать их все в одном задании на печать.

Например, первый форматтер содержит текст, который заполняет первую страницу и немного вторую страницу. Несмотря на то, что осталось еще оставить второй шрифт, я хочу, чтобы второй форматтер печатал на третьей странице. Итак, прежде чем печатать другой форматтер, запустите новую страницу.

Я не знаю, сколько страниц один форматир будет заполняться во время компиляции, потому что это зависит от пользовательского ввода. Может быть, 1, 2 или более.

Я слышал, что мне нужно использовать UIPrintPageRenderer, поэтому я прочитал его документы и попробовал это:

// I'm using webviews here because I don't want to write 2 pages worth of markup...
// it should be the same anyway. The two webviews display different wikipedia articles
// Also, don't judge my variable names. I'm lazy and this is just test code...
let formatter = webView.viewPrintFormatter()
let formatter1 = webView2.viewPrintFormatter()

formatter.contentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)
formatter1.contentInsets = UIEdgeInsets(top: 72, left: 72, bottom: 72, right: 72)

let renderer = UIPrintPageRenderer()
renderer.addPrintFormatter(formatter, startingAtPageAt: 0)
renderer.addPrintFormatter(formatter1, startingAtPageAt: formatter.pageCount)

printController.printPageRenderer = renderer
printController.present(animated: true, completionHandler: nil)

Чтобы добавить второй формат печати, я использовал formatter.pageCount в качестве второго аргумента. Я надеялся, что он добавит второй форматтер после последней страницы первого. Но это не так. Он печатал только материал во втором формате.

Я напечатал formatter.pageCount и нашел, что его значение равно 0.

Я совершенно смущен. Как я могу получить, сколько страниц будет заполняться форматированием?

Я также попытался реализовать свой собственный рендерер:

class MyRenderer: UIPrintPageRenderer {
    override func drawPrintFormatter(_ printFormatter: UIPrintFormatter, forPageAt pageIndex: Int) {
        printFormatter.draw(in: self.printableRect, forPageAt: pageIndex)
    }
}

Но тогда он просто падает, когда контроллер взаимодействия с печатью показал:

Попробовал получить веб-блокировку из потока, отличного от основного потока или веб-потока. Это может быть результатом вызова UIKit из вторичного потока. Сбой сейчас...

Что я сделал неправильно в своем коде?

Ответы

Ответ 1

Как и в случае с документом, UIPrintFormatter нуждается во всей информации, прежде чем вычислять количество страниц для печати в формате.

UIPrintFormatter публикует интерфейс, который позволяет вам указать стартовая страница для задания на печать и поля вокруг напечатанного содержание; учитывая, что информация плюс контент, формат печати вычисляет количество страниц для задания печати. ​​

Так что этого не произойдет, если UIPrintFormatter не начнет печатать содержимое.

Так как UIPrintPageRenderer может использовать UIPrintFormatter, он может фактически получить количество страниц, связанных с форматированием, и все, что вам нужно сделать, - это переопределить numberOfPages, чтобы настроить разные форматы на каждой странице.

Ниже приведен пример кода от Apple. Что делает то же самое - добавление нескольких форматировщиков (UIMarkupTextPrintFormatter) на каждой странице.

Здесь переопределяет numberOfPages:

- (NSInteger)numberOfPages {
    self.printFormatters = nil;
    [self setupPrintFormatters];
    return [super numberOfPages];
}

И прикрепите форматтер к каждой странице здесь:

  /*
     Iterate through the recipes setting each of their html representations into 
     a UIMarkupTextPrintFormatter and add that formatter to the printing job.
     */
    - (void)setupPrintFormatters {
        NSInteger page = 0;
        CGFloat previousFormatterMaxY = CGRectGetMinY(self.contentArea);

        for (Recipe *recipe in recipes) {
            NSString *html = recipe.htmlRepresentation;

            UIMarkupTextPrintFormatter *formatter = [[UIMarkupTextPrintFormatter alloc] initWithMarkupText:html];
            [formatterToRecipeMap setObject:recipe forKey:formatter];

            // Make room for the recipe info
            UIEdgeInsets contentInsets = UIEdgeInsetsZero;
            contentInsets.top = previousFormatterMaxY + self.recipeInfoHeight;
            if (contentInsets.top > CGRectGetMaxY(self.contentArea)) {
                // Move to the next page
                page++;
                contentInsets.top = CGRectGetMinY(self.contentArea) + self.recipeInfoHeight;
            }
            formatter.contentInsets = contentInsets;

            // Add the formatter to the renderer at the specified page
            [self addPrintFormatter:formatter startingAtPageAtIndex:page];

            page = formatter.startPage + formatter.pageCount - 1;
            previousFormatterMaxY = CGRectGetMaxY([formatter rectForPageAtIndex:page]);

        }
    }

Короче говоря, он вычисляет номер страницы на основе области содержимого, вставки содержимого и затем прикрепляет форматтер к странице, вызывая API:

 [self addPrintFormatter:formatter startingAtPageAtIndex:page];

Таким образом, у Renderer есть информация о форматировании для каждой страницы. Вы можете найти полный код здесь

Надеюсь, это поможет.