在iOS 4.2和以后芽腾,應(yīng)用程序可以添加對(duì)本地打印機(jī)的打印內(nèi)容的支持。盡管并非所有應(yīng)用程序都需要打印支持惭载,但是如果應(yīng)用程序用于創(chuàng)建內(nèi)容(例如文字處理器或繪圖程序)、進(jìn)行購(gòu)買(打印訂單確認(rèn))和用戶可能合理地希望永久記錄的其他任務(wù)含长,那么打印通常是一個(gè)有用的特性。
本章說明如何向應(yīng)用程序添加打印支持陪腌。在高級(jí)別上,您的應(yīng)用程序創(chuàng)建打印作業(yè)强岸,提供準(zhǔn)備打印的圖像和PDF文檔的數(shù)組蝌箍、單個(gè)圖像或PDF文檔、任何內(nèi)置打印格式化程序類的實(shí)例或自定義頁(yè)面渲染。
術(shù)語(yǔ)說明:印刷作業(yè)(print job)的概念在本章中出現(xiàn)了很多次甚亭。打印作業(yè)是一種工作單元,它不僅包括要打印的內(nèi)容暇唾,還包括打印中使用的信息瘸味,例如打印機(jī)的身份、打印作業(yè)的名稱以及打印的質(zhì)量和方向枯冈。
IOS中的打印設(shè)計(jì)簡(jiǎn)單直觀
為了打印,用戶點(diǎn)擊通常位于導(dǎo)航欄或工具欄中的按鈕炫加,該按鈕與用戶想要打印的視圖或選定項(xiàng)目相關(guān)聯(lián)。然后驹针,應(yīng)用程序呈現(xiàn)了打印選項(xiàng)的視圖。用戶選擇打印機(jī)和各種選項(xiàng)苛蒲,然后請(qǐng)求打印。應(yīng)用程序被要求從其內(nèi)容生成打印輸出或提供可打印數(shù)據(jù)或文件URL。請(qǐng)求的打印作業(yè)被假脫機(jī)蔫浆,控件返回到應(yīng)用程序洗显。如果目標(biāo)打印機(jī)當(dāng)前不忙,打印立即開始玄组。如果打印機(jī)已經(jīng)在打印嵌灰,或者如果在隊(duì)列中它之前有作業(yè)迁匠,則打印作業(yè)將保留在iOS打印隊(duì)列中,直到它移動(dòng)到隊(duì)列的頂部并被打印亡哄。
打印界面
用戶看到的與打印相關(guān)的第一件事是打印按鈕。打印按鈕通常是導(dǎo)航欄或工具欄上的bar button item。打印按鈕應(yīng)該在邏輯上使用應(yīng)用程序呈現(xiàn)的內(nèi)容宦焦;如果用戶點(diǎn)擊按鈕,應(yīng)用程序應(yīng)該打印該內(nèi)容。盡管打印按鈕可以是任何自定義按鈕锄码,但是建議您使用圖6-1所示的系統(tǒng)barButtonItem痛悯。這是一個(gè)UIBarButtonItem
對(duì)象,用UIBarButtonSystemItemAction
常量指定,可以在接口生成器中創(chuàng)建該對(duì)象,也可以通過調(diào)用initWithBarButtonSystemItem:target:action:
方法.
當(dāng)用戶點(diǎn)擊打印按鈕時(shí), 應(yīng)用程序的控制器對(duì)象會(huì)接受到打印動(dòng)作消息. 控制器的響應(yīng)是準(zhǔn)備打印和顯示打印機(jī)選項(xiàng)的視圖. 這些選項(xiàng)包括目標(biāo)打印機(jī)(從可發(fā)現(xiàn)打印機(jī)列表中選擇), 副本的數(shù)量, 有時(shí)還包含要打印的頁(yè)的范圍. 如果所選打印機(jī)能夠進(jìn)行雙面打印, 用戶可以選擇單面或雙面打印輸出. 如果用戶選擇不打印, 他們點(diǎn)擊選項(xiàng)視圖范圍以外的部分(ipad上), 或者點(diǎn)擊cancel按鈕(iPhone和iPod touch上)來取消打印機(jī)選項(xiàng)視圖.
打印選項(xiàng)界面的類型取決于設(shè)備. 在iPad上, UIKit框架使用popover視圖來顯示選項(xiàng), 如圖6-2.
在iPhone或者iPod上, UIKit將打印選項(xiàng)界面從底部往上滑出, 如圖6-3.
一旦你提交了打印作業(yè), 那么打印作業(yè)正在進(jìn)行或者正在打印隊(duì)列中等待打印, 用戶可以通過雙擊home按鈕從而顯示多任務(wù)UI界面, 選擇打印中心(Print Center)來查看其狀態(tài). 打印中心(如圖6-4)是一個(gè)后臺(tái)系統(tǒng)應(yīng)用程序, 該程序顯示打印隊(duì)列總的作業(yè)順序, 包括當(dāng)前正在打印的作業(yè), 該程序只有當(dāng)前打印作業(yè)正在進(jìn)行時(shí)才有用.
在打印中心, 用戶可以點(diǎn)擊打印作業(yè)來獲取該作業(yè)的具體信息(如圖6-5)也可以取消正在打印或排隊(duì)中的打印作業(yè).
iOS中的打印原理
APP使用UIKit中打印API來收集打印作業(yè)的要素, 包括要打印的內(nèi)容和與打印作業(yè)相關(guān)的信息. 然后顯示打印選項(xiàng)界面. 用戶作出選擇點(diǎn)擊打印按鈕. 在某些情況下, UIKit框架要求APP將打印的內(nèi)容繪制出來, UIKit會(huì)將這些繪制內(nèi)容記錄為PDF數(shù)據(jù), 然后UIKit會(huì)將打印數(shù)據(jù)提交給打印子系統(tǒng).
打印系統(tǒng)會(huì)做一些事情來完成打印作業(yè). 當(dāng)UIKit將打印數(shù)據(jù)傳遞給打印子系統(tǒng)時(shí), 它將此數(shù)據(jù)寫入存儲(chǔ)單元中. 它還捕獲有關(guān)打印作業(yè)的信息, 打印系統(tǒng)在先進(jìn)先出隊(duì)列中管理著組合的打印數(shù)據(jù)和每個(gè)打印作業(yè)的metadata. 設(shè)備上的多個(gè)應(yīng)用可以向打印子系統(tǒng)提交多個(gè)打印作業(yè), 所有這些作業(yè)都放在打印隊(duì)列中. 每個(gè)設(shè)備都有一個(gè)隊(duì)列用于所有打印作業(yè), 不管它來自那個(gè)APP或目的打印機(jī).
當(dāng)打印作業(yè)到了隊(duì)列的頂部時(shí), 系統(tǒng)打印守護(hù)進(jìn)程(這里稱之為printd
)考慮目標(biāo)打印機(jī)的要求, 并在必要的時(shí)候?qū)⒋蛴?shù)據(jù)轉(zhuǎn)換為打印機(jī)識(shí)別的數(shù)據(jù)類型. 打印系統(tǒng)會(huì)向用戶報(bào)告諸如"沒紙了"之類的錯(cuò)誤警報(bào). 它還以編程方式向打印中心報(bào)告打印作業(yè)的進(jìn)程情況, 打印中心先士卒如打印作業(yè)的page 2 of 5
之類的信息.
UIKit中的打印API
UIKit中print API包括8個(gè)類和一個(gè)protocol. 這些類的實(shí)例和實(shí)現(xiàn)協(xié)議的delegate在runtime具有的關(guān)系如圖6-7所示.
打印支持概述
在高層上, 有兩個(gè)方法可以將打印能力添加到APP中. 如果你正在使用UIActivityViewController
, 并且如果你不需要控制用戶選擇過程的能力, 包括是否可以選擇頁(yè)面范圍或覆蓋紙張的選擇. 那么你可以添加打印活動(dòng). 否則, 必須使用類UIPrintInteractionController
來向APP中添加打印能力.
當(dāng)用戶告訴APP打印時(shí), 類UIPrintInteractionController
的單例可以向你提供APP指定應(yīng)該做啥的能力, 它包括有關(guān)打印作業(yè)(UIPrintInfo
)和紙張大小和打印內(nèi)容的區(qū)域(UIPrintPaper
)的信息. 它還可以引用實(shí)現(xiàn)UIPrintInteractionControllerDelegate
來進(jìn)一步設(shè)置打印行為的delegate對(duì)象.
更重要的是, 打印交互控制器可以讓你的APP提供要打印的內(nèi)容. UIPrintInteractionController
類提供了三種不同打印方式:
- 靜態(tài)image或PDF文件. 對(duì)于簡(jiǎn)單的內(nèi)容, 可以使用打印交互控制的
printingItem
或printingItems
屬性來提供image(各種格式的), PDF文件或多個(gè)image或PDF文件 - Print formatters. 如果需要自動(dòng)回流(reflow)打印文本和Html內(nèi)容, 可以將內(nèi)置的print formatter的實(shí)例賦值給打印交互控制器的
printFormatter
屬性 - Page renderers. Page renderer可以讓你自定義打印內(nèi)容, 讓你完全控制頁(yè)面布局, 包括頁(yè)眉和頁(yè)腳. 要使用page renderer, 必須先編寫page renderer的子類, 然后將其實(shí)例賦值給打印交互控制器的
printPageRenderer
屬性.
重要: 上面提到四個(gè)屬性是互斥的, 也就是說, 如果為其中一個(gè)屬性賦值, UIKit會(huì)將其他三個(gè)屬性的值置為nil.
有了這樣一系列的選項(xiàng)卒蘸,你的應(yīng)用程序的最佳選擇是什么?表6-1闡明了作出這一決定的因素。
6-1 決定如何打印APP內(nèi)
如果... | 就... |
---|---|
APP可以訪問可直接打印的內(nèi)容(圖片或PDF) | 使用printingItem 或者printingItems 屬性 |
想打印單個(gè)image或PDF并且可以讓用戶選擇頁(yè)面范圍 | 使用printingItem 屬性 |
您希望打印純文本或HTML文檔(并且不希望附加內(nèi)容, 如頁(yè)眉和頁(yè)腳) | 將一個(gè)UISimpleTextPrintFormatter 或UIMarkupTextPrintFormatter 對(duì)象賦值給printFormatter 屬性, 而且print-formatter對(duì)象使用plain或者HTML文本初始化. |
你希望打印一個(gè)UIKit視圖中的內(nèi)容(并且不需要打印其他附件內(nèi)容,頁(yè)面頁(yè)腳) | 從需要打印的視圖中獲取一個(gè)UIViewPrintFormatter 對(duì)象, 并將其賦值給printFormatter 屬性. |
你希望打印的頁(yè)面顯示頁(yè)面頁(yè)腳, 和增加的頁(yè)號(hào) | 將UIPrintPageRenderer 對(duì)象賦值給printPageRenderer 屬性. 你可以將UIPrintPageRenderer 的子類賦值給屬性, 這樣你就可以自定義頁(yè)面渲染. |
您希望對(duì)打印的內(nèi)容有最大程度的控制 | 將UIPrintPageRenderer 的子類實(shí)例賦值給屬性printPageRenderer ,并繪制所打印的所有內(nèi)容县恕。 |
打印工作流
打印圖片, PDF或其他可打印的內(nèi)容的一般步驟如下:
獲取
UIPrintInteractionController
單例(可選, 但強(qiáng)烈建議)創(chuàng)建一個(gè)
UIPrintInfo
對(duì)象, 設(shè)置一些屬性比如, output type, job name, 打印方向; 然后將該對(duì)象賦值給打印交互控制器的printInfo
屬性. (Apple強(qiáng)烈建議你設(shè)置output type和job name)
如果你設(shè)置printInfo對(duì)象,那么UIKit會(huì)給打印作業(yè)設(shè)置默認(rèn)的屬性(比如, 作業(yè)名稱(job name)是APP的名稱)(可選)將一個(gè)委托controller賦值給delegate屬性, 該委托控制器必須實(shí)現(xiàn)
UIPrintInteractionControllerDelegate
協(xié)議. 通過這個(gè)委托可以做很多事. 委托可以在打印選項(xiàng)呈現(xiàn)和撤銷時(shí), 以及打印作業(yè)開始和結(jié)束時(shí)做出適當(dāng)?shù)捻憫?yīng). 它可讓打印交互控制器返回到父視圖控制. 另外, 默認(rèn)情況下, UIKit根據(jù)輸出類型(output type)表明APP正在打印的內(nèi)容類型,這樣可以讓系統(tǒng)選擇默認(rèn)的紙張大小和可打印區(qū)域. 如果APP需要對(duì)打印紙張的大小進(jìn)行更多的控制, 則可以重寫標(biāo)準(zhǔn)行為. 后續(xù)內(nèi)容會(huì)具體講解.-
對(duì)下面
UIPrintInteractionController
的四個(gè)屬性之一進(jìn)行賦值:- 將包含PDF或image數(shù)據(jù)引用的
NSData
,NSURL
,UIImage
,ALAsset
對(duì)象賦值給printingItem
屬性 - 如果要打印一組image或者PDF文檔,則可以將一組和打印內(nèi)容相關(guān)的
NSData
,NSURL
,UIImage
,ALAsset
對(duì)象賦值給printingItems
屬性 - 如果要對(duì)打印內(nèi)容進(jìn)行自定義布局可以給賦值一個(gè)
UIPrintFormatter
對(duì)象給printFormatter
屬性 - 給
printPageRenderer
賦值一個(gè)UIPrintPageRenderer
對(duì)象.
- 將包含PDF或image數(shù)據(jù)引用的
如果在前一個(gè)步驟中賦值了page renderer對(duì)象, 那么該對(duì)象通常是
UIPrintPageRenderer
子類對(duì)象. 當(dāng)UIKit請(qǐng)求打印時(shí),繪制用于打印的內(nèi)容. 它還可以在頁(yè)眉頁(yè)腳中繪制內(nèi)容. 自定義page renderer必須重寫至少一個(gè)draw
方法, 如果它正在繪制部分內(nèi)容(不包括頁(yè)眉頁(yè)腳), 則它必須計(jì)算并返回打印作業(yè)的頁(yè)數(shù). (注意你可以使用UIPrintPageRender
類型對(duì)象連接一系列打印模式)(可選)如果你使用page renderer, 那么用
UIPrintPageRender
的具體子類來創(chuàng)建一個(gè)或多個(gè)對(duì)象, 然后通過addPrintFormatter:startingAtPageAtIndex:
方法來給頁(yè)面設(shè)置具體的page render對(duì)象. 你可以將一組page renderer對(duì)象賦值給屬性printFormatters
.如果當(dāng)前的設(shè)備時(shí)iPad, 可以通過
presentFromBarButtonItem:animated:completionHandler:
或presentFromRect:inView:animated:completionHandler:
來展示打印界面, 如果是iPhone或者iPod, 那么可以通過presentAnimated:completionHandler:
方法. 另外, 可以通過printInteractionControllerParentViewController:
delegate方法來將打印界面嵌入到現(xiàn)在的界面中. 如果你的APP使用了一個(gè)活動(dòng)表(iOS 6及以后版本), 你可以添加一個(gè)打印活動(dòng)項(xiàng).
到這, 步驟的不同取決于你是否打印靜態(tài)內(nèi)容, 是否使用print formatter或者page renderer.
將打印機(jī)中準(zhǔn)備打印的內(nèi)容打印出來
iOS打印系統(tǒng)接受某些對(duì)象并直接打印他們的內(nèi)容, 該過程中系統(tǒng)會(huì)盡量減少APP的參與. 這些對(duì)象是NSData, NSURL, UIImage, 和ALAsset類的實(shí)例, 它們必須包含或引用圖片數(shù)據(jù)或PDF數(shù)據(jù). 圖像數(shù)據(jù)可以涉及所有這些對(duì)象類型, PDF數(shù)據(jù)有NSURL對(duì)象引用或有NSData對(duì)象包含. 這里有些對(duì)這些對(duì)象額外的要求:
- 圖像必須以圖像I/O框架支持的格式。有關(guān)這些格式的列表剂桥,請(qǐng)參閱UIImage類API中的支持圖像格式忠烛。
- NSURL對(duì)象必須使用
file:
,assets-library:
scheme, 或者任何可以返回具有注冊(cè)協(xié)議(registered protocol)的NSData的內(nèi)容(例如,QuickLook的x-apple-ql-id:
) - 將打印機(jī)就緒對(duì)象賦值給類
UIPrintInteractionController
單例的printingItem
或printingItems
屬性美尸。您可以將一個(gè)打印機(jī)就緒對(duì)象賦值給printingItem
和將打印機(jī)準(zhǔn)備對(duì)象數(shù)組賦值給printingItems
屬性冤议。
注意:通過提供打印機(jī)就緒對(duì)象, 會(huì)將打印內(nèi)容的布局交由打印系統(tǒng)控制, 所以設(shè)置諸如打印方向等是沒有效果的. 如果你的APP想控制布局, 你必須自己做繪圖.
另外, 如果APP對(duì)其打印內(nèi)容使用printingItems
保存, 則無(wú)法在printer-options視圖中指定頁(yè)面范圍, 即使有多個(gè)頁(yè)面, 并且showsPageRange
屬性值為YES.
在將對(duì)象分配給這些屬性之前,應(yīng)該使用UIPrintInteractionController的類方法之一來驗(yàn)證對(duì)象师坎。例如恕酸,如果具有圖像的UTI,并且希望驗(yàn)證圖像是否已準(zhǔn)備好打印機(jī)胯陋,則可以首先使用printableUTIs類方法測(cè)試它蕊温,該方法返回對(duì)打印系統(tǒng)有效的一組UTI:
if ([[UIPrintInteractionController printableUTIs] containsObject:mysteryImageUTI])
printInteractionController.printingItem = mysteryImage;
類似地, 在設(shè)置printingItems
和printingItem
屬性前, 你可以使用UIPrintInteractionController
的canPrintURL:
和canPrintData:
類方法來驗(yàn)證NSURL
和NSData
對(duì)象是否可以直接被打印, 尤其是在打印PDF時(shí).
代碼6-1展示在打印包含PDF數(shù)據(jù)的NSData
對(duì)象之前, 驗(yàn)證是否有效的方法. 并且在打印選項(xiàng)界面顯示提供讓用戶控制page-range的選項(xiàng).
代碼6-1 打印PDF文檔同時(shí)提供page-range選項(xiàng)的能力
- (IBAction)printContent:(id)sender {
UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
if (pic && [UIPrintInteractionController canPrintData: self.myPDFData] ) {
pic.delegate = self;
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = [self.path lastPathComponent];
printInfo.duplex = UIPrintInfoDuplexLongEdge;
pic.printInfo = printInfo;
pic.showsPageRange = YES;
pic.printingItem = self.myPDFData;
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *pic, BOOL completed, NSError *error) {
self.content = nil;
if (!completed && error)
NSLog(@"FAILED! due to error in domain %@ with error code %u",
error.domain, error.code);
};
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[pic presentFromBarButtonItem:self.printButton animated:YES
completionHandler:completionHandler];
} else {
[pic presentAnimated:YES completionHandler:completionHandler];
}
}
處理多個(gè)打印對(duì)象步驟和上面一樣, 唯一區(qū)別是設(shè)置printingItems
屬性,而不是printingItem
:
pic.printingItems = [NSArray arrayWithObjects:imageViewOne.image, imageViewTwo.image, imageViewThree.image, nil];
使用Print Formatters和Page Renders
Print formatter和page renderer是用來在多頁(yè)中布局打印內(nèi)容的對(duì)象. 通過starting page, 內(nèi)容區(qū)域, 內(nèi)容它們可以設(shè)置開始頁(yè)的內(nèi)容和技術(shù)最后一頁(yè)的內(nèi)容. 也能夠設(shè)置也中打印區(qū)域的margin. 兩者間的區(qū)別有:
- Print formatter只能布局單頁(yè)內(nèi)容(一段文本或HTML, 一個(gè)view等等)
- Page renderer可以讓你添加頁(yè)眉頁(yè)腳, 進(jìn)行自定義繪制等操作, 如果需要,Page renderer可以使用 print formatters對(duì)象來完成他們的大部分工作
如果您創(chuàng)建了UIPrintPageRenderer
的自定義子類遏乔,您可以部分或全部繪制每個(gè)頁(yè)面的可打印內(nèi)容义矛。Page renderer可以具有一個(gè)或多個(gè)與可打印內(nèi)容的特定頁(yè)面或頁(yè)面范圍相關(guān)聯(lián)的print formatters
為打印作業(yè)設(shè)置布局屬性
為了確定打印內(nèi)容在頁(yè)面上的區(qū)域, UIPrintFormatter
類為實(shí)體子類定義了4個(gè)關(guān)鍵的屬性. 這些屬性和類UIPrintPageRenderder
的footerHeight
和headerHeight
, 類UIPrintPaper
的paperSize
和printableRect
屬性, 共同決定了多頁(yè)打印任務(wù)的布局. 圖6-8描述了該布局.
屬性 | 描述 |
---|---|
contentInsets | 可打印矩形區(qū)域內(nèi)的點(diǎn)到頂部,左側(cè),右側(cè)三邊的距離, 這些值設(shè)置打印內(nèi)容的內(nèi)邊距(margin), 雖然可以被maximumContentHeight和maximumContentWidth值所覆蓋. 頂部邊距只對(duì)第一頁(yè)有效. |
maximumContentHeight | 設(shè)置內(nèi)容區(qū)域的最大高度, 包括了頁(yè)眉頁(yè)腳的高度. UIKit會(huì)比較該屬性和頁(yè)面高度-頂部邊距(topInset)的值, 然后取較小的值. |
startPage | 用于formatter開始繪制的內(nèi)容頁(yè). 此值是從0開始的, 比如page renderer告訴formatter開始打印第三頁(yè), 那么page renderer會(huì)將startPage設(shè)置為2 |
maximumContentWidth | 設(shè)置內(nèi)容區(qū)域的最大寬度. UIKit會(huì)比較該屬性和頁(yè)面高度-左邊距(leftInset)的值-右邊距(rightInset), 然后取較小的值. |
注意:如果你使用
UIPrintInteractionController
的屬性printFormatter
, 那么UIPrintPageRenderer
對(duì)象將無(wú)效了, 也即是說, 你無(wú)法設(shè)置頁(yè)眉頁(yè)腳了.
UIPrintFormatter
會(huì)使用上表的四個(gè)屬性,來計(jì)算打印內(nèi)容的頁(yè)數(shù), 然后將頁(yè)數(shù)保存在只讀屬性pageCount
中.
使用Print Formatter
UIKit可以讓你設(shè)置打印job的單個(gè)print formatter. 如果你有純文本或HTML文檔, 這可能是一個(gè)有用的功能, 因?yàn)閁IKit為這些類型的文本內(nèi)容定義了print formatter實(shí)體子類. 這些子類還可以讓你打印UIKit視圖中的內(nèi)容.
UIPrintFormatter
類是系統(tǒng)為打印格式化定義的虛基類. 目前, iOS提供了以下實(shí)體的UIPrintFormatter
子類:
-
UIViewPrintFormatter
-自動(dòng)在多個(gè)頁(yè)面上顯示視圖的內(nèi)容. 若要獲取視圖的print formatter對(duì)象, 請(qǐng)使用view的viewPrintFormatter
方法.- 并非所有的內(nèi)置UIKit視圖都支持打印. 目前只有
UIWebView
,UITextView
,MKMapView
這幾個(gè)視圖知道如何繪制打印的內(nèi)容. - 視圖的print formatter不應(yīng)該用來打印自定義視圖. 如要打印自定義視圖的內(nèi)容, 請(qǐng)使用
UIPrintPageRenderer
替代.
- 并非所有的內(nèi)置UIKit視圖都支持打印. 目前只有
-
UISimpleTextPrintFormatter
-自動(dòng)繪制和布局純文本文檔. 該formatter允許你設(shè)置text的全局性屬性, 如font, color, alignment, 已經(jīng)換行模式. -
UIMarkupTextPrintFormatter
-自動(dòng)繪制和布局HTML文檔.
注意:
UIPrintFormatter
類并不讓自定義繼承, 如果需要自定義布局, 你可以使用page renderer
盡管下面的內(nèi)容還是使用單個(gè)print formatter(并且沒有page renderer), 但是在關(guān)于打印 formatter的許多信息都適用于和page renderer結(jié)合使用.
打印純文本或HTML
虛度APP包含用戶想打印的文本內(nèi)容. 如果內(nèi)容為純文本或HTML文本, 那么你可以訪問屏幕顯示內(nèi)容后面的字符串, 然后使用UISimpleTextPrintFormatter
或UIMarkupTextPrintFormatter
來布局和繪制這些內(nèi)容. 你只需要使用這些內(nèi)容的后面的字符串來創(chuàng)建print formatter實(shí)例, 然后設(shè)置layout屬性. 再將該print formatter賦值到UIPrintInteractionController
的實(shí)例.
代碼6-2告訴你使用一個(gè)UIMarkupTextPrintFormatter
對(duì)象來打印HTML文檔. 它會(huì)在打印區(qū)域內(nèi)加上內(nèi)邊距. 你可以通過屬性printPaper
來確定打印區(qū)域. 想看更詳細(xì)的代碼參考蘋果官方demoUIKit Printing with UIPrintInteractionController and UIViewPrintFormatter
代碼清單6-2 打印HTML文檔
- (IBAction)printContent:(id)sender {
UIPrintInteractionController *pic = [UIPrintInteractionController sharedPrintController];
pic.delegate = self;
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = self.documentName;
pic.printInfo = printInfo;
UIMarkupTextPrintFormatter *htmlFormatter = [[UIMarkupTextPrintFormatter alloc]
initWithMarkupText:self.htmlString];
htmlFormatter.startPage = 0;
htmlFormatter.contentInsets = UIEdgeInsetsMake(72.0, 72.0, 72.0, 72.0); // 1 inch margins
pic.printFormatter = htmlFormatter;
pic.showsPageRange = YES;
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
if (!completed && error) {
NSLog(@"Printing could not complete because of error: %@", error);
}
};
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[pic presentFromBarButtonItem:sender animated:YES completionHandler:completionHandler];
} else {
[pic presentAnimated:YES completionHandler:completionHandler];
}
}
使用UISimpleTextPrintFormatter
對(duì)象布局和打印純文本文檔的過程幾乎是相同的。但是盟萨,這個(gè)對(duì)象的類包括允許您設(shè)置打印文本的字體凉翻、顏色和對(duì)齊方式的屬性。
打印view的中內(nèi)容
你可以使用UIViewPrintFormatter
實(shí)例來布局和打印系統(tǒng)view的內(nèi)容. UIKit會(huì)自動(dòng)為創(chuàng)建該view的print formatter對(duì)象. 通常視圖繪制的代碼和視圖print formatter中的繪制打印內(nèi)容代碼一樣. 目前iOS支持視圖打印的view有UIWebView
, UITextView
, MKMapView
. 為了獲取視圖的print formatter對(duì)象你需要調(diào)用view的viewPrintFormatter
方法, 然后設(shè)置formatter的layout和starting page等屬性并將formatter設(shè)置為打印交互控制器的printFormatter
屬性. 另外, 如果你想自己繪制部分的打印內(nèi)容, 那么你可以將該view的print formatter賦值給UIPrintPageRenderer
對(duì)象. 代碼6-3展示了使用view的print formatter來打印UIWebView
中的內(nèi)容.
代碼清單6-3 打印webView中的內(nèi)容
- (void)printWebPage:(id)sender {
UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *printController, BOOL completed, NSError *error) {
if(!completed && error){
NSLog(@"FAILED! due to error in domain %@ with error code %u",
error.domain, error.code);
}
};
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = [urlField text];
printInfo.duplex = UIPrintInfoDuplexLongEdge;
controller.printInfo = printInfo;
controller.showsPageRange = YES;
UIViewPrintFormatter *viewFormatter = [self.myWebView viewPrintFormatter];
viewFormatter.startPage = 0;
controller.printFormatter = viewFormatter;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[controller presentFromBarButtonItem:printButton animated:YES completionHandler:completionHandler];
}else
[controller presentAnimated:YES completionHandler:completionHandler];
}
使用Page Renderer
一個(gè)頁(yè)面渲染器是UIPrintPageRenderer
的子類的實(shí)例, 它繪制打印作業(yè)的全部或部分內(nèi)容. 若要使用需要子類化它, 并將添加子類到項(xiàng)目中, 然后將該子類的實(shí)例賦值到打印交互控制器的UIPrintPageRenderer
屬性. 一個(gè)page renderer可以和一個(gè)或多個(gè)print formatter相關(guān)連, 這樣可以將內(nèi)容繪制和print formatter的繪制結(jié)合使用.
Page renderer可繪制和布局打印的內(nèi)容, 也可使用print formatter來處理特定頁(yè)面上的內(nèi)容. 因此, 為了獲取多個(gè)formatter, 你可以使用UIPrintPageRenderer
類自身來和多個(gè)formatter相關(guān)聯(lián). 但大多數(shù)情況下是使用UIPrintPageRenderer
的子類.
注意:如果要打印頁(yè)眉頁(yè)腳信息, 比如, 重復(fù)文檔標(biāo)題和遞增顯示頁(yè)數(shù). 則必須使用
UIPrintPageRenderer
的自定義子類
UIPrintPageRenderer
基類包含頁(yè)面計(jì)數(shù)和頁(yè)眉頁(yè)腳高度這些屬性. 它還聲明了幾個(gè)方法, 重寫這些方法可以繪制特定部分的:頁(yè)眉, 頁(yè)腳, 內(nèi)容本身, 或者結(jié)合page render和formatter來繪制內(nèi)容.
設(shè)置Page renderer的Attributes
如果使用page renderer繪制每頁(yè)的頁(yè)眉頁(yè)腳時(shí), 你需要設(shè)置頁(yè)眉頁(yè)腳的高度. 你可以通過屬性headerHeight
和footerHeight
來設(shè)置. 如果這些高度屬性的值為0(默認(rèn)), 那么drawHeaderForPageAtIndex:InRect:
和drawFooterForPageAtIndex:inRect:
方法不會(huì)被調(diào)用.
如果你的page renderer打算去繪制頁(yè)面中的內(nèi)容, 也就是說, 在頁(yè)眉和頁(yè)腳之間的那部分區(qū)域. 那么你應(yīng)該在子類中重寫numberOfPages
方法, 在方法中計(jì)算和返回需要繪制的頁(yè)數(shù). 如果你的page renderer關(guān)聯(lián)了一個(gè)print formatter, 那么print formatter會(huì)計(jì)算頁(yè)面的數(shù)量, 并繪制除了也沒和頁(yè)腳以外的所有內(nèi)容.
如果單獨(dú)使用page renderer時(shí), 每頁(yè)的布局都需要你自己考慮. 在計(jì)算layout時(shí), 你可以考慮headerHeight
, footerHeight
, paperRect
和printableRect
這四個(gè)UIPrintPageRenderer
的屬性(后面兩個(gè)只讀)值. 如果你結(jié)合print formatter使用時(shí), 你需要同時(shí)考慮的布局因素還包括contentInset
, maximumContentHeight
和maximumContentWidth
這幾個(gè)UIPrintFormatter
的屬性值.
實(shí)現(xiàn)Page renderer中的繪圖方法
當(dāng)APP使用page renderer去繪制可打印的內(nèi)容時(shí), UIKit會(huì)為請(qǐng)求的內(nèi)容的每一頁(yè)調(diào)用以下方法. 注意, UIKit不會(huì)保證按頁(yè)順序去調(diào)用這些方法. 另外如果用戶請(qǐng)求打印部分頁(yè)面(即, 他們制定了頁(yè)面范圍), UIKit只會(huì)為需要打印的頁(yè)面調(diào)用這些方法.
注意: 如果你繪制image或者PDF這些可打印內(nèi)容時(shí), 使用的是非UIKit API(比如, Quartz API), 那么你需要翻轉(zhuǎn)UIKit的坐標(biāo)系, 將坐標(biāo)系改為L(zhǎng)LO型的.
在drawPageAtIndex:inRect:
方法中會(huì)按照下表的列表方法的順序來調(diào)用其他方法. 如果你想全面控制打印內(nèi)容的繪制可以將下面這些方法重寫.
重寫... | 可以... |
---|---|
drawHeaderForPageAtIndex:inRect: |
繪制頁(yè)眉的內(nèi)容. 當(dāng)headerHeight為0時(shí), 該方法不會(huì)調(diào)用. |
drawContentForPageAtIndex:inRect: |
繪制打印作用的內(nèi)容(即頁(yè)眉頁(yè)腳間的區(qū)域) |
drawPrintFormatter:forPageAtIndex: |
將自定義繪圖和有print formatter執(zhí)行的繪圖混合. 當(dāng)給每一頁(yè)關(guān)聯(lián)一個(gè)print formatter時(shí), 該方法會(huì)被調(diào)用. |
drawFooterForPageAtIndex:inRect: |
繪制頁(yè)腳內(nèi)容. 當(dāng)footerHeight為0時(shí), 該方法不會(huì)調(diào)用. |
所有的這些繪圖方法都是在當(dāng)前繪圖上下文(由UIGraphicsGetCurrentContext
函數(shù)返回)中繪制. 傳入這些繪圖方法的rect參數(shù)定義的區(qū)域包含頁(yè)面頁(yè)腳, 內(nèi)容區(qū)域, 整個(gè)頁(yè)面區(qū)域, 以及頁(yè)面的origin, 基于ULO坐標(biāo)系.
代碼6-4舉例說明drawHeaderForPageAtIndex:inRect:
和drawFooterForPageAtIndex:inRect:
方法的實(shí)現(xiàn). 它們使用CGRectGetMaxX
和CGRectGetMaxY
來計(jì)算在打印區(qū)域坐標(biāo)系中的footerRect
和headerRect
中的文本位置.
代碼清單6-4 繪制頁(yè)眉頁(yè)腳
- (void)drawHeaderForPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)headerRect {
UIFont *font = [UIFont fontWithName:@"Helvetica" size:12.0];
CGSize titleSize = [self.jobTitle sizeWithFont:font];
//center title in header
CGFloat drawX = CGRectGetMaxX(headerRect)/2 - titleSize.width/2;
CGFloat drawY = CGRectGetMaxY(headerRect) - titleSize.height;
CGPoint drawPoint = CGPointMake(drawX, drawY);
[self.jobTitle drawAtPoint:drawPoint withFont: font];
}
- (void)drawFooterForPageAtIndex:(NSInteger)pageIndex inRect:(CGRect)footerRect {
UIFont *font = [UIFont fontWithName:@"Helvetica" size:12.0];
NSString *pageNumber = [NSString stringWithFormat:@"%d.", pageIndex+1];
// page number at right edge of footer rect
CGSize pageNumSize = [pageNumber sizeWithFont:font];
CGFloat drawX = CGRectGetMaxX(footerRect) - pageNumSize.width - 1.0;
CGFloat drawY = CGRectGetMaxY(footerRect) - pageNumSize.height;
CGPoint drawPoint = CGPointMake(drawX, drawY);
[pageNumber drawAtPoint:drawPoint withFont: font];
}
將一個(gè)或多個(gè)Print formatter和一個(gè)Page renderer配合使用
一個(gè)page renderer可以和一個(gè)或多個(gè)print formatter結(jié)合使用來繪制打印內(nèi)容. 比如, APP可能會(huì)使用UISimpleTextPrintFormatter
對(duì)象來繪制打印頁(yè)中的文本內(nèi)容, 但是使用一個(gè)page renderer來在每頁(yè)的頁(yè)眉中繪制文檔標(biāo)題. 或者, APP使用兩個(gè)print formatter, 一個(gè)用來繪制第一頁(yè)header信息和開始部分內(nèi)容, 另一個(gè)用來繪制頁(yè)面中的其他內(nèi)容, 然后才會(huì)使用page renderer來繪制兩部分的分割線.
正如前面所講, 可以將單個(gè)print formatter賦值給UIPrintInteractionController
的屬性printFormatter
. 但是如果你使用一個(gè)page renderer和print formatter的話, 你需要做如下兩件事來將print formatter和page renderer關(guān)聯(lián)起來:
- 用一個(gè)數(shù)組將print formatter裝起來, 然后將數(shù)組賦值給
printFormatters
- 使用
addPrintFormatter:startingAtPageAtIndex:
方法來添加每個(gè)print formatter
在將print formatter設(shè)置到page renderer之前, 要將print formatter的layout屬性設(shè)置好, 包括打印作業(yè)的起始頁(yè)(startPage
). 當(dāng)你設(shè)置這些屬性后, UIPrintFormatter
會(huì)計(jì)算打印任務(wù)的頁(yè)數(shù). 注意如果你通過方法addPrintFormatter:startingAtPageAtIndex:
方法來添加起始頁(yè), 那么屬性startPage
的值會(huì)被覆蓋.
page renderer可以將自己的繪制操作和print formatter繪制操作的結(jié)合起來對(duì)某個(gè)頁(yè)進(jìn)行繪制. page renderer繪制print formatter無(wú)法繪制的內(nèi)容, 然后調(diào)用drawInRect:forPageAtIndex:
方法來繪制余下的部分內(nèi)容. page render也可以繪制一種"遮蓋"效果, 方法時(shí)先讓print formatter繪制內(nèi)容, 然后在內(nèi)容上面繪制一層內(nèi)容.
測(cè)試APP的內(nèi)容打印
蘋果官方說iOS4.2之后提供了一個(gè)Printer Simulator供開發(fā)者測(cè)試, 集成在Xcode中, 但我沒找到!!! 網(wǎng)上應(yīng)該可以下載.
常見的打印任務(wù)
打印的大部分任務(wù)基本交由系統(tǒng)完成, APP需要做的是, 確認(rèn)設(shè)備是否具有打印功能, 總結(jié)打印選項(xiàng)界面. 然后提供一個(gè)打印按鈕供用戶進(jìn)入打印界面, 之后為該按鈕綁定一個(gè)打印事件. 所以該按鈕的響應(yīng)方法是關(guān)鍵, 也是我們APP需要自己處理的關(guān)鍵部分, 下面內(nèi)容將如何實(shí)現(xiàn)打印按鈕的事件方法.
測(cè)試打印能力
有些iOS設(shè)備是不支持打印的. 所以在要寫打印代碼之前你需要判斷是否支持打印. 如果該iOS設(shè)備不支持打印, 你不能顯示任何有關(guān)打印的界面. UIPrintInteractionController
的類方法isPrintingAvailable
可以判斷當(dāng)前設(shè)備是否支持打印. 代碼6-5展示了打印能力的判斷代碼示例.
代碼清單6-5 更加打印能力判斷是否顯示打印按鈕
- (void)viewDidLoad {
if (![UIPrintInteractionController isPrintingAvailable])
[myPrintButton removeFromSuperView];
// other tasks...
}
注意:上面直接移除按鈕, 而不是影藏或者disable等操作, 因?yàn)槿绻O(shè)備不支持打印, 那么該設(shè)備就不會(huì)有可能支持的可能了, 所以直接移除是推薦的
設(shè)置打印作業(yè)信息
一個(gè)UIPrintInfo
對(duì)象包含了很多有關(guān)打印作業(yè)的信息, 尤其是:
- output type(輸出類型, 指明了內(nèi)容的類型)
- print-job name(名字)
- printing orientation(朝向)
- duplex mode(單雙頁(yè)打印)
- identifier of the selected(選擇的打印記得標(biāo)識(shí)符)
你不必對(duì)UIPrintInfo
的所有屬性賦值, 你只需要選擇幾個(gè)需要的關(guān)鍵屬性賦值, 其他屬性UIKit會(huì)幫你設(shè)置為默認(rèn)值.(如果可以, 你都不必創(chuàng)建UIPrintInfo
對(duì)象, 但不建議這樣做, why? 前面講過)
在大多數(shù)情況下, 你會(huì)對(duì)打印作業(yè)設(shè)置一些信息, 比如output type. 你可以通過類方法printInfo
來獲取UIPrintInfo
對(duì)象, 然后對(duì)該對(duì)象設(shè)置一些屬性. 將設(shè)置好的對(duì)象復(fù)制給UIPrintInteractionController
的printInfo
屬性. 代碼6-6, 展示了這一過程.
代碼清單6-6 設(shè)置printInfo
屬性
UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
printInfo.outputType = UIPrintInfoOutputGeneral;
printInfo.jobName = [self.path lastPathComponent];
printInfo.duplex = UIPrintInfoDuplexLongEdge;
controller.printInfo = printInfo;
UIPrintInfo
的一個(gè)屬性是用來控制打印方向的:portrait(豎立)和landscape(橫向). 你可以選擇合適的方向來打印你的內(nèi)容, 另外, 當(dāng)打印的內(nèi)容的寬度大于高度的話, 推薦使用橫向(landscape)打印方向. 代碼6-7,展示了設(shè)置打印方向
代碼6-7 設(shè)置打印方向
UIPrintInteractionController *controller = [UIPrintInteractionController sharedPrintController];
// other code here...
UIPrintInfo *printInfo = [UIPrintInfo printInfo];
UIImage *image = ((UIImageView *)self.view).image;
printInfo.outputType = UIPrintInfoOutputPhoto;
printInfo.jobName = @"Image from PrintPhoto";
printInfo.duplex = UIPrintInfoDuplexNone;
// only if drawing...
if (!controller.printingItem && image.size.width > image.size.height)
printInfo.orientation = UIPrintInfoOrientationLandscape;
設(shè)置紙張的大小, 方向, 單/雙頁(yè)打印
默認(rèn)情況下, UIKit根據(jù)目標(biāo)打印機(jī)和打印作業(yè)的輸出類型設(shè)置一組默認(rèn)的紙張大小. 如, 根據(jù)UIPrintInfo
中的output type來指定. 例如, 如果輸出是類型UIPrintInfoOutputPhoto
, 默認(rèn)紙張大小是4x6英寸, A6或其他一些標(biāo)準(zhǔn), 這和當(dāng)?shù)氐囊恍?biāo)準(zhǔn)有關(guān). 如果輸出類型是UIPrintInfoOutputGeneral
或UIPrintInfoOutputGray
, 則默認(rèn)大小是US 字母(8 1/2x11英寸), A4或一些其他標(biāo)準(zhǔn)的大小設(shè)置.
對(duì)于大多數(shù)APP來說, 這些默認(rèn)紙張是可以接受的. 然而有些APP可能需要特殊的紙張尺寸. 比如生成宣傳小冊(cè)子或者賀卡等等, 那么就需要定制自己的紙張尺寸. 在這種情況下, 打印交互控制器的委托可以實(shí)現(xiàn)UIPrintInteractionControllerDelegate
的printInteractionController:choosePaper:
方法來返回一個(gè)UIPrintPaper
對(duì)象, 該對(duì)象表示可用紙張和可打印矩形區(qū)域的最佳組合. delegate有兩個(gè)方式來找到合適的UIPrintPaper
對(duì)象, 它可以檢查傳入的UIPrintPaper
數(shù)組來找到一個(gè)最合適的對(duì)象. 或者delegate可以通過UIPrintPaper
的類方法bestPaperForPageSize:withPapersFromArray:
來找到最佳對(duì)象. 代碼6-8展示了delegate方法的實(shí)現(xiàn)
代碼清單6-8 方法bestPaperForPageSize:withPapersFromArray:
的實(shí)現(xiàn)
- (UIPrintPaper *)printInteractionController:(UIPrintInteractionController *)pic
choosePaper:(NSArray *)paperList {
// custom method & properties...
CGSize pageSize = [self pageSizeForDocumentType:self.document.type];
return [UIPrintPaper bestPaperForPageSize:pageSize
withPapersFromArray:paperList];
}
通常, 使用自定義 page renderer在會(huì)計(jì)算頁(yè)面數(shù)量時(shí),計(jì)算紙張的大小. 如果APP需要向用戶展示紙張大小的選項(xiàng), APP則必須自己實(shí)現(xiàn)該UI界面, 然后在打印交互控制器中使用用戶選擇的紙張. 例如:
// Create a custom CGSize for 8.5" x 11" paper.
CGSize custompapersize = CGSizeMake(8.5 * 72.0, 11.0 * 72.0);
UIPrintInfo
類還允許您提供其他設(shè)置鸯旁,例如打印方向噪矛、選擇的打印機(jī)和單雙頁(yè)模式(如果打印機(jī)支持雙頁(yè)打印).
將打印集成到用戶界面中
這里有兩個(gè)方式將打印集成到用戶界面中:
- 使用打印交互控制器
UIPrintInteractionController
- 從activity sheet中展示(iOS6.0及以后)
使用打印交互控制器來呈現(xiàn)打印選項(xiàng)界面
UIPrintInteractionController
聲明了三種展示打印選項(xiàng)界面的方法, 沒種都有自己的動(dòng)畫:
-
presentFromBarButtonItem:animated:completionHandler:
從導(dǎo)航欄或toolbar上的按鈕上popover一個(gè)view出來(通常是從打印按鈕的位置出來) -
presentFromRect:inView:animated:completionHandler:
從一個(gè)view中的指定rect區(qū)域中popover -
presentAnimated:completionHandler:
從屏幕底部向上滑出一個(gè)sheet頁(yè)面
前兩個(gè)方法針對(duì)的是iPad設(shè)備, 第三個(gè)方法時(shí)針對(duì)iPod和iPhone設(shè)備. 你在代碼中可以通過判斷UI_USER_INTERFACE_IDIOM
常量值是否為UIUserInterfaceIdiomPad
或UIUserInterfaceIdiomPhone
來判斷使用哪一個(gè)方法. 代碼6-9展示該判斷
代碼清單6-9 根據(jù)設(shè)備類型來使用presenting方法
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
[controller presentFromBarButtonItem:self.printButton animated:YES
completionHandler:completionHandler];
} else {
[controller presentAnimated:YES completionHandler:completionHandler];
}
如果你在iPad中調(diào)用了iPhone類的presenting方法, 那么會(huì)從當(dāng)前window的frame中popover一個(gè)view, 如果你在iPhone設(shè)備中調(diào)用了iPad的presenting方法, 那么會(huì)從底部slide up一個(gè)sheet頁(yè)面.
如果你調(diào)用presenting方法來顯示一個(gè)打印選項(xiàng)界面, 但打印選項(xiàng)界面已經(jīng)顯示了, 那么UIPrintInteractionController
會(huì)隱藏打印選項(xiàng)界面, 你必須重新調(diào)用presenting方法來顯示一個(gè)打印選項(xiàng)界面.
如果你設(shè)置了打印機(jī)的ID,或單雙頁(yè)設(shè)置,那么在打印選項(xiàng)界面, 默認(rèn)選擇你設(shè)置的值. 如果你讓用戶選擇打印頁(yè)面范圍, 那么你必須對(duì)打印交互控制器的showsPageRange
屬性設(shè)置為YES(默認(rèn)是NO). 但是如果你通過屬性printingItems
來進(jìn)行打印, 或者打印的頁(yè)數(shù)為1, 那么即使你將showsPageRange
設(shè)置為YES.
如果你想打印界面顯示在一個(gè)特殊的view中, 那么你可以實(shí)現(xiàn)UIPrintInteractionControllerDelegate
方法printInteractionControllerParentViewController:
, 該方法需要你提供打印交互控制器的父控制器.
從activity sheet中顯示打印
要使用activity sheet顯示打印界面也簡(jiǎn)單, 但注意這里有兩個(gè)警告:
- APP無(wú)法控制用戶是否可以選擇頁(yè)面范圍
- APP不能使用delegate方法來重寫打印行為, 列如手動(dòng)覆蓋紙張大小選擇的行為.
使用此技術(shù), APP必須創(chuàng)建包含以下內(nèi)容的activity items的數(shù)組:
- 一個(gè)
UIPrintInfo
對(duì)象 - 一個(gè)page renderer對(duì)象, print formatter對(duì)象, printable item
- 任何其他activity item, 只要你覺得可以
然后你調(diào)用initWithActivityItems:applicationActivities:
方法, 第一次參數(shù)傳activity items數(shù)組, 第二參數(shù)為nil. 最后, 你使用標(biāo)準(zhǔn)的控制器present*方法, 將activity sheet present出來. 具體細(xì)節(jié)可看UIActivityViewController Class Reference和UIActivity Class Reference
響應(yīng)打印作業(yè)的完成和錯(cuò)誤
前面已經(jīng)講過如何present打印交互控制器, 其中有個(gè)參數(shù)我們沒講到就是completionHandler. 這個(gè)參數(shù)的類型是UIPrintInteractionCompletionHandler
,一個(gè)block. 用來結(jié)果回調(diào)處理的. 通沉咳铮可以在這個(gè)block中處理打印成功/失敗的信息. 比如打印失敗可以,將原因分析出來, 然后顯示給用戶查看. 代碼6-10, 展示了completionHandler的實(shí)現(xiàn)
代碼清單6-10 實(shí)現(xiàn)completionHandler block
void (^completionHandler)(UIPrintInteractionController *, BOOL, NSError *) =
^(UIPrintInteractionController *pic, BOOL completed, NSError *error) {
self.content = nil;
if (!completed && error)
NSLog(@"FAILED! due to error in domain %@ with error code %u",
error.domain, error.code);
};
當(dāng)打印結(jié)束后, UIKit會(huì)將UIPrintInteractionController
擁有的實(shí)例釋放掉, 所以不需要你在completionHandler中做這些工作. 如果打印失敗了, 在completionHandler中會(huì)傳入NSError
, 有個(gè)domain為UIPrintErrorDomain
和錯(cuò)誤碼, 這些都會(huì)定義在UIPrintError.h
中. 在幾乎所有的情況下铺罢,這些錯(cuò)誤碼指示的是編程錯(cuò)誤,因此通常不需要通知用戶残炮。但也會(huì)由于打印文件(由文件方案NSURL對(duì)象所定位)導(dǎo)致錯(cuò)誤, 這可能需要提示用戶.