android連線印表機列印
Android使用者經常只在自己的裝置上檢視內容,但有時顯示某人的螢幕不是一種充分的方式來共享資訊。 您可以從Android應用程式列印資訊,讓使用者可以透過應用程式檢視更大版本的內容,或與未使用您應用程式的使用者分享。 列印還允許他們建立不依賴於具有裝置,足夠的電池電量或無線網路連線的資訊的快照。
在Android 4.4(API級別19)及更高版本中,框架提供了直接從Android應用程式列印影象和文件的服務。
本培訓介紹如何在應用程式中啟用列印功能,包括列印影象,HTML頁面和建立自定義文件以進行列印。
一:列印照片
拍攝和分享照片是移動裝置最流行的用途之一。 如果應用程式拍攝照片,顯示照片或允許使用者共享影象,則應考慮在應用程式中啟用列印這些影象。
本節將向您介紹如何使用v4支援庫PrintHelper
類列印影象:
Android支援庫PrintHelper類提供了一種列印影象的簡單方法。 該類有一個單一的佈局選項,setScaleMode(),它允許您列印兩個選項之一:
SCALE_MODE_FIT - 此選項調整影象大小,以便整個影象顯示在頁面的可列印區域內。
SCALE_MODE_FILL - 此選項縮放影象,以便它填充頁面的整個可列印區域。 選擇此設定意味著不列印影象的頂部和底部,或左右邊緣的某些部分。 如果未設定縮放模式,則此選項為預設值。
setScaleMode()的縮放選項保持影象的現有寬高比不變。 以下程式碼示例顯示如何建立PrintHelper類的例項,設定縮放選項,並開始列印過程:
privatevoid doPhotoPrint(){PrintHelper photoPrinter =newPrintHelper(getActivity()); photoPrinter.setScaleMode(PrintHelper.SCALE_MODE_FIT);Bitmap bitmap =BitmapFactory.decodeResource(getResources(), R.drawable.droids); photoPrinter.printBitmap("droids.jpg - test print", bitmap);此方法可以稱為選單項的操作。 注意,不總是支援的操作(例如列印)的選單項應該放在溢位選單中。 有關更多資訊,請參閱Action Bar設計指南。}
呼叫printBitmap()方法後,不需要從應用程式執行進一步的操作。 將顯示Android列印使用者介面,允許使用者選擇印表機和列印選項。 然後使用者可以列印影象或取消操作。 如果使用者選擇列印影象,則會建立列印作業,並在系統欄中顯示列印通知。
如果要在列印輸出中包括除影象之外的其他內容,則必須構建列印文件。 有關建立要列印的文件的資訊,請往下看。
二:列印HTML文件
在Android上列印超出簡單照片的內容需要在列印文件中合成文字和圖形。 Android框架提供了一種使用HTML來編寫文件並使用最少的程式碼列印文件的方法。
在Android 4.4(API級別19)中,WebView類已更新為啟用列印HTML內容。
該類允許您載入本地HTML資源或從網路下載頁面,建立列印作業並將其移交給Android的列印服務。
本節將向您展示如何快速構建包含文字和圖形的HTML文件,並使用WebView進行列印。
1.載入HTML文件
使用WebView列印HTML文件涉及載入HTML資源或將HTML文件構建為字串。 本節介紹如何構建HTML字串並將其載入到WebView以進行列印。
此檢視物件通常用作活動佈局的一部分。 但是,如果您的應用程式沒有使用WebView,您可以專門為列印目的建立類的例項。 建立此自定義列印檢視的主要步驟如下:
(1)建立在載入HTML資源後啟動列印作業的WebViewClient。
(2)將HTML資源載入到WebView物件中。
下面的程式碼示例演示瞭如何建立一個簡單的WebViewClient並載入一個動態建立的HTML文件:
privateWebView mWebView;privatevoid doWebViewPrint(){// Create a WebView object specifically for printingWebView webView =newWebView(getActivity()); webView.setWebViewClient(newWebViewClient(){publicboolean shouldOverrideUrlLoading(WebView view,String url){returnfalse;}@Overridepublicvoid onPageFinished(WebView view,String url){Log.i(TAG,"page finished loading "+ url); createWebPrintJob(view); mWebView =null;}});// Generate an HTML document on the fly:String htmlDocument ="<html><body><h1>Test Content</h1><p>Testing, "+"testing, testing...</p></body></html>"; webView.loadDataWithBaseURL(null, htmlDocument,"text/HTML","UTF-8",null);// Keep a reference to WebView object until you pass the PrintDocumentAdapter// to the PrintManager mWebView = webView;}
注意:確保生成列印作業的呼叫發生在您在上一節中建立的WebViewClient的onPageFinished()方法中。
如果不等到頁面載入完成,列印輸出可能不完整或空白,或可能完全失敗。
注意:上面的示例程式碼儲存了一個WebView物件的例項,因此在建立列印作業之前不會對其進行垃圾回收。 確保您在自己的實現中執行相同操作,否則列印過程可能會失敗。
如果要在頁面中包含圖形,請將圖形檔案放在專案的assets /目錄中,並在loadDataWithBaseURL()方法的第一個引數中指定基本URL,如以下程式碼示例所示:
webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,"text/HTML","UTF-8",null);您還可以通過使用loadUrl()替換loadDataWithBaseURL()方法來載入要列印的網頁,如下所示。
// Print an existing web page (remember to request INTERNET permission!): webView.loadUrl("http://developer.android.com/about/index.html");
使用WebView建立列印文件時,應注意以下限制:
(1)您無法向文件中新增頁首或頁尾(包括頁碼)。
(2)HTML文件的列印選項不包括列印頁面範圍的功能,例如:不支援列印10頁HTML文件的第2頁到第4頁。
(3)WebView的一個例項一次只能處理一個列印作業。
(4)不支援包含CSS列印屬性(如橫向屬性)的HTML文件。
(5)您不能在HTML文件中使用JavaScript來觸發列印。
注意:包含在佈局中的WebView物件的內容也可以在載入文件後列印。
2.建立列印作業
在建立WebView並載入HTML內容後,您的應用程式幾乎完成了它的列印過程的一部分。 接下來的步驟是訪問PrintManager,建立列印介面卡,最後建立列印作業。
以下示例說明如何執行這些步驟:
privatevoid createWebPrintJob(WebView webView){// Get a PrintManager instancePrintManager printManager =(PrintManager) getActivity().getSystemService(Context.PRINT_SERVICE);// Get a print adapter instancePrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();// Create a print job with name and adapter instanceString jobName = getString(R.string.app_name)+" Document";PrintJob printJob = printManager.print(jobName, printAdapter,newPrintAttributes.Builder().build());// Save the job object for later status checking mPrintJobs.add(printJob);}此示例儲存物件的例項以供應用程式使用,這不是必需的。 您的應用程式可能會使用此物件來跟蹤列印作業正在處理時的進度。 當您希望在應用程式中監視列印作業的完成,失敗或使用者取消操作的狀態時,此方法非常有用。 不需要建立應用程式內通知,因為列印框架會自動為列印作業建立系統通知。
三:列印自定義文件
對於一些應用程式,如繪圖應用程式,頁面佈局應用程式和其他專注於圖形輸出的應用程式,建立漂亮的列印頁面是一個關鍵特性。 在這種情況下,列印影象或HTML文件是不夠的。 這些型別應用程式的列印輸出需要精確控制進入頁面的所有內容,包括字型,文字流,分頁符,頁首,頁尾和圖形元素。
為您的應用程式建立完全自定義的列印輸出需要比前面討論的方法更多的程式設計投資。 您必須構建與列印框架通訊的元件,調整為印表機設定,繪製頁面元素和管理多個頁面上的列印。
本節將向您介紹如何與列印管理器連線,建立列印介面卡並構建列印內容
1.連線到列印管理器
當應用程式直接管理列印過程時,從使用者收到列印請求後的第一步是連線到Android列印框架並獲取PrintManager類的例項。
此類允許您初始化列印作業並開始列印生命週期。 以下程式碼示例顯示如何獲取列印管理器並開始列印過程。
privatevoid doPrint(){// Get a PrintManager instancePrintManager printManager =(PrintManager) getActivity().getSystemService(Context.PRINT_SERVICE);// Set job name, which will be displayed in the print queueString jobName = getActivity().getString(R.string.app_name)+" Document";// Start a print job, passing in a PrintDocumentAdapter implementation// to handle the generation of a print document printManager.print(jobName,newMyPrintDocumentAdapter(getActivity()),null);//}
上面的示例程式碼演示瞭如何命名列印作業並設定類的例項,該類負責處理列印生命週期的步驟。
列印介面卡類的實現將在下一節中討論。
注意:print()方法中的最後一個引數接受一個PrintAttributes物件。
您可以使用此引數向列印框架提供提示,並根據先前的列印週期提供預設選項,從而改善使用者體驗。 您還可以使用此引數設定更適合正在列印的內容的選項,例如在列印處於該方向的照片時將方向設定為橫向
2.建立列印介面卡
列印介面卡與Android列印框架互動並處理列印過程的步驟。此過程要求使用者在建立要列印的文件之前選擇印表機和列印選項。這些選擇可以影響最終輸出,因為使用者選擇具有不同輸出能力,不同頁面大小或不同頁面方向的印表機。當進行這些選擇時,列印框架要求介面卡佈置並生成列印文件,以準備最終輸出。一旦使用者點選列印按鈕,框架獲取最終列印文件並將其傳遞給列印提供者用於輸出。在列印過程中,使用者可以選擇取消列印操作,因此列印介面卡還必須監聽並對取消請求作出反應。
PrintDocumentAdapter抽象類設計用於處理列印生命週期,它有四個主要的回撥方法。您必須在列印介面卡中實現這些方法,以便與列印框架正確互動:
(1)onStart() - 在列印程序的開始呼叫一次。如果應用程式有任何一次性準備任務要執行,例如獲取要列印的資料的快照,請在此處執行。不需要在介面卡中實現此方法。
(2)onLayout() - 每次使用者更改影響輸出的列印設定(例如不同的頁面大小或頁面方向)時呼叫,為應用程式提供計算要列印的頁面佈局的機會。至少,此方法必須返回列印文件中預期的頁數。
(3)onWrite() - 呼叫將列印的頁面轉換為要列印的檔案。此方法可以在每次onLayout()呼叫後呼叫一次或多次。
(4)onFinish() - 在列印過程結束時呼叫一次。如果您的應用程式有任何一次性拆卸任務要執行,請在此處執行。不需要在介面卡中實現此方法。
以下部分介紹如何實現佈局和寫入方法,這對於列印介面卡的功能至關重要。
注意:這些介面卡方法在應用程式的主執行緒上呼叫。如果你期望這些方法在你的實現中的執行需要大量的時間,實現它們在一個單獨的執行緒中執行。例如,您可以封裝佈局或在單獨的AsyncTask物件中列印文件編寫工作
3.計算列印文件資訊
在PrintDocumentAdapter類的實現中,您的應用程式必須能夠指定正在建立的文件型別,並計算列印作業的總頁數,並提供有關列印頁面大小的資訊。 在介面卡中實現onLayout()方法進行這些計算,並提供有關PrintDocumentInfo類中列印作業的預期輸出的資訊,包括頁數和內容型別。
以下程式碼示例顯示了PrintDocumentAdapter的onLayout()方法的基本實現:
@Overridepublicvoid onLayout(PrintAttributes oldAttributes,PrintAttributes newAttributes,CancellationSignal cancellationSignal,LayoutResultCallback callback,Bundle metadata){// Create a new PdfDocument with the requested page attributes mPdfDocument =newPrintedPdfDocument(getActivity(), newAttributes);// Respond to cancellation requestif(cancellationSignal.isCancelled()){ callback.onLayoutCancelled();return;}// Compute the expected number of printed pagesint pages = computePageCount(newAttributes);if(pages >0){// Return print information to print frameworkPrintDocumentInfo info =newPrintDocumentInfo.Builder("print_output.pdf").setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(pages);.build();// Content layout reflow is complete callback.onLayoutFinished(info,true);}else{// Otherwise report an error to the print framework callback.onLayoutFailed("Page count calculation failed.");}}
onLayout()方法的執行可以有三個結果:完成,取消或失敗,在佈局的計算無法完成的情況下。 您必須通過呼叫PrintDocumentAdapter.LayoutResultCallback物件的相應方法來指定其中一個結果。
注意:onLayoutFinished()方法的boolean引數指示自上次請求以來佈局內容是否實際已更改。
正確設定此引數允許列印框架避免不必要地呼叫onWrite()方法,基本上快取先前寫入的列印文件並提高效能。
onLayout()的主要工作是計算給定印表機屬性時預期為輸出的頁數。 如何計算此數字在很大程度上取決於應用程式如何佈局列印頁面。 下面的程式碼示例顯示了一個實現,其中頁數由列印方向決定:
privateint computePageCount(PrintAttributes printAttributes){int itemsPerPage =4;// default item count for portrait modeMediaSize pageSize = printAttributes.getMediaSize();if(!pageSize.isPortrait()){// Six items per page in landscape orientation itemsPerPage =6;}// Determine number of print itemsint printItemCount = getPrintItemCount();return(int)Math.ceil(printItemCount / itemsPerPage);}
4.編寫列印文件檔案
當需要將列印輸出寫入檔案時,Android列印框架呼叫應用程式的PrintDocumentAdapter類的onWrite()方法。方法的引數指定應該寫入哪些頁面以及要使用的輸出檔案。然後,您的此方法的實現必須將每個請求的內容頁面呈現為多頁PDF文件檔案。當此過程完成時,您呼叫回撥物件的onWriteFinished()方法。
注意:Android列印框架可以每次呼叫onLayout()時呼叫onWrite()方法一次或多次。為此,當列印內容佈局未改變時,重要的是將onLayoutFinished()方法的布林引數設定為false,以避免列印文件的不必要的重寫。
注意:onLayoutFinished()方法的布林引數指示自上次請求以來佈局內容是否實際已更改。正確設定此引數允許列印框架避免不必要地呼叫onLayout()方法,基本上快取先前寫入的列印文件並提高效能。
以下示例演示了使用類建立PDF檔案的此過程的基本機制:
@Overridepublicvoid onWrite(finalPageRange[] pageRanges,finalParcelFileDescriptor destination,finalCancellationSignal cancellationSignal,finalWriteResultCallback callback){// Iterate over each page of the document,// check if it's in the output range.for(int i =0; i < totalPages; i++){// Check to see if this page is in the output range.if(containsPage(pageRanges, i)){// If so, add it to writtenPagesArray. writtenPagesArray.size()// is used to compute the next output page index. writtenPagesArray.append(writtenPagesArray.size(), i);PdfDocument.Page page = mPdfDocument.startPage(i);// check for cancellationif(cancellationSignal.isCancelled()){ callback.onWriteCancelled(); mPdfDocument.close(); mPdfDocument =null;return;}// Draw page content for printing drawPage(page);// Rendering is complete, so page can be finalized. mPdfDocument.finishPage(page);}}// Write PDF document to filetry{ mPdfDocument.writeTo(newFileOutputStream( destination.getFileDescriptor()));}catch(IOException e){ callback.onWriteFailed(e.toString());return;}finally{ mPdfDocument.close(); mPdfDocument =null;}PageRange[] writtenPages = computeWrittenPages();// Signal the print framework the document is complete callback.onWriteFinished(writtenPages);...}
此示例將PDF頁面內容的呈現委派給drawPage()方法,這將在下一節中討論。
與佈局一樣,onWrite()方法的執行可以有三個結果:完成,取消或在內容不能寫入的情況下失敗。 您必須通過呼叫PrintDocumentAdapter.WriteResultCallback物件的相應方法指定其中一個結果。
注意:渲染文件以進行列印可能是資源密集型操作。 為了避免阻塞應用程式的主使用者介面執行緒,您應該考慮在單獨的執行緒上執行頁面呈現和寫入操作,例如在AsyncTask中。 有關使用非同步任務等執行執行緒的更多資訊,請參閱
5.繪圖PDF頁面內容
當應用程式列印時,應用程式必須生成PDF文件並將其傳遞到Android列印框架進行列印。 您可以使用任何PDF生成庫用於此目的。 本課將介紹如何使用PrintedPdfDocument類根據內容生成PDF頁面。
PrintedPdfDocument類使用Canvas物件在PDF頁面上繪製元素,類似於在活動佈局上繪圖。 您可以使用Canvas繪製方法在列印頁面上繪製元素。 以下示例程式碼演示瞭如何使用以下方法在PDF文件頁面上繪製一些簡單元素:
privatevoid drawPage(PdfDocument.Page page){Canvas canvas = page.getCanvas();// units are in points (1/72 of an inch)int titleBaseLine =72;int leftMargin =54;Paint paint =newPaint(); paint.setColor(Color.BLACK); paint.setTextSize(36); canvas.drawText("Test Title", leftMargin, titleBaseLine, paint); paint.setTextSize(11); canvas.drawText("Test paragraph", leftMargin, titleBaseLine +25, paint); paint.setColor(Color.BLUE); canvas.drawRect(100,100,172,172