Как 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) на каждой странице.
Это переопределяет число страниц здесь:
- (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 имеет информацию о форматере для каждой страницы. Вы можете найти полный код здесь
Надеюсь, это поможет.