iOS繪圖和打印編程指導(dǎo)(六)-iOS打印

在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:方法.

圖5-1 系統(tǒng)的print按鈕

當(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.


圖6-2 iPad中的打印選項(xiàng)視圖

在iPhone或者iPod上, UIKit將打印選項(xiàng)界面從底部往上滑出, 如圖6-3.


圖6-3 iPhone上的打印選項(xiàng)頁(yè)

一旦你提交了打印作業(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í)才有用.
圖6-4 打印中心

在打印中心, 用戶可以點(diǎn)擊打印作業(yè)來獲取該作業(yè)的具體信息(如圖6-5)也可以取消正在打印或排隊(duì)中的打印作業(yè).


圖6-5 打印中心-打印作業(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之類的信息.

圖6-6 打印系統(tǒng)的總體架構(gòu)

UIKit中的打印API


UIKit中print API包括8個(gè)類和一個(gè)protocol. 這些類的實(shí)例和實(shí)現(xiàn)協(xié)議的delegate在runtime具有的關(guān)系如圖6-7所示.


圖6-7 UIKit打印對(duì)象間的關(guān)系

打印支持概述

在高層上, 有兩個(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)容, 可以使用打印交互控制的printingItemprintingItems屬性來提供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è)UISimpleTextPrintFormatterUIMarkupTextPrintFormatter對(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)容的一般步驟如下:

  1. 獲取UIPrintInteractionController單例

  2. (可選, 但強(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的名稱)

  3. (可選)將一個(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ì)具體講解.

  4. 對(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ì)象.
  5. 如果在前一個(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ì)象連接一系列打印模式)

  6. (可選)如果你使用page renderer, 那么用UIPrintPageRender的具體子類來創(chuàng)建一個(gè)或多個(gè)對(duì)象, 然后通過addPrintFormatter:startingAtPageAtIndex:方法來給頁(yè)面設(shè)置具體的page render對(duì)象. 你可以將一組page renderer對(duì)象賦值給屬性printFormatters.

  7. 如果當(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單例的printingItemprintingItems屬性美尸。您可以將一個(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è)置printingItemsprintingItem屬性前, 你可以使用UIPrintInteractionControllercanPrintURL:canPrintData:類方法來驗(yàn)證NSURLNSData對(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)鍵的屬性. 這些屬性和類UIPrintPageRenderderfooterHeightheaderHeight, 類UIPrintPaperpaperSizeprintableRect屬性, 共同決定了多頁(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è)腳了.

圖6-8 多頁(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替代.
  • 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)容后面的字符串, 然后使用UISimpleTextPrintFormatterUIMarkupTextPrintFormatter來布局和繪制這些內(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è)腳的高度. 你可以通過屬性headerHeightfooterHeight來設(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, paperRectprintableRect這四個(gè)UIPrintPageRenderer的屬性(后面兩個(gè)只讀)值. 如果你結(jié)合print formatter使用時(shí), 你需要同時(shí)考慮的布局因素還包括contentInset, maximumContentHeightmaximumContentWidth這幾個(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). 它們使用CGRectGetMaxXCGRectGetMaxY來計(jì)算在打印區(qū)域坐標(biāo)系中的footerRectheaderRect中的文本位置.
代碼清單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ù)制給UIPrintInteractionControllerprintInfo屬性. 代碼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). 如果輸出類型是UIPrintInfoOutputGeneralUIPrintInfoOutputGray, 則默認(rèn)大小是US 字母(8 1/2x11英寸), A4或一些其他標(biāo)準(zhǔn)的大小設(shè)置.

對(duì)于大多數(shù)APP來說, 這些默認(rèn)紙張是可以接受的. 然而有些APP可能需要特殊的紙張尺寸. 比如生成宣傳小冊(cè)子或者賀卡等等, 那么就需要定制自己的紙張尺寸. 在這種情況下, 打印交互控制器的委托可以實(shí)現(xiàn)UIPrintInteractionControllerDelegateprintInteractionController: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常量值是否為UIUserInterfaceIdiomPadUIUserInterfaceIdiomPhone來判斷使用哪一個(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 ReferenceUIActivity 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ò)誤, 這可能需要提示用戶.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末韭赘,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子势就,更是在濱河造成了極大的恐慌泉瞻,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件苞冯,死亡現(xiàn)場(chǎng)離奇詭異袖牙,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)舅锄,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門鞭达,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人皇忿,你說我怎么就攤上這事畴蹭。” “怎么了鳍烁?”我有些...
    開封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵叨襟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我幔荒,道長(zhǎng)糊闽,這世上最難降的妖魔是什么梳玫? 我笑而不...
    開封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任,我火速辦了婚禮右犹,結(jié)果婚禮上汽纠,老公的妹妹穿的比我還像新娘。我一直安慰自己傀履,他們只是感情好虱朵,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著钓账,像睡著了一般碴犬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上梆暮,一...
    開封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天服协,我揣著相機(jī)與錄音,去河邊找鬼啦粹。 笑死偿荷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的唠椭。 我是一名探鬼主播跳纳,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼贪嫂!你這毒婦竟也來了寺庄?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤力崇,失蹤者是張志新(化名)和其女友劉穎斗塘,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體亮靴,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馍盟,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了茧吊。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贞岭。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖饱狂,靈堂內(nèi)的尸體忽然破棺而出曹步,到底是詐尸還是另有隱情,我是刑警寧澤休讳,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布讲婚,位于F島的核電站,受9級(jí)特大地震影響俊柔,放射性物質(zhì)發(fā)生泄漏筹麸。R本人自食惡果不足惜活合,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望物赶。 院中可真熱鬧白指,春花似錦、人聲如沸酵紫。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)奖地。三九已至橄唬,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間参歹,已是汗流浹背仰楚。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留犬庇,地道東北人僧界。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像臭挽,于是被迫代替她去往敵國(guó)和親捂襟。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容