Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Develop -- Training(十四) -- 打印內容

Develop -- Training(十四) -- 打印內容

編輯:關於Android編程

Android 用戶經常在他們的設備上查看完整的內容,但是有時候在一個屏幕上不能完全地顯示某個人的一些信息。能夠打印信息從你的 Android 應用程序給用戶看見較大的內容從你的應用程序或者分享其他人的應用程序,但不使用你的應用程序。打印也允許他們創建一個快照信息,而不依賴於有一個設備、足夠的電池電量、或者一個無線網連接。

在 Android 4.4 或者更高,該框架提供了打印圖片和文檔的服務,直接從 Android 應用程序調用。這次培訓描述如何打印應用程序,包括印刷圖像、HTML頁面和創建自定義文件打印。

打印圖片


拍照和分享圖片是一種最流行的移動設備的使用。如果你的應用程序拍照,顯示他們,或者允許用戶分享圖片,你應該考慮在你的應用程序上可以打印那些圖片。Android Support Library 提供了一個方便的函數,能夠圖片打印使用很少的代碼和簡單的布局。

PrintHelper 類是 support v4 中的,提供了打印圖片。

1.打印一張圖片

PrintHelper 類提供了一個簡單的方法來打印圖片。這個類有一個布局選擇,setScaleMode() 方法,允許你二選一:

SCALE_MODE_FIT - - 整個圖像顯示在頁面的打印區域
SCALE_MODE_FILL - - 填滿整個頁面的打印區域。選擇這個設置意味著,頂部和底部的一部分,或左右圖像的邊緣不打印。如果不設置模式的話,SCALE_MODE_FILL 是默認值。

兩個縮放選項 setScaleMode() 方法保持現有的圖像的長寬比不變。 以下代碼示例顯示創建 PrintHelper 類,設置擴展選項,並開始打印過程。

private void doPhotoPrint() {
    PrintHelper photoPrinter = new PrintHelper(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 或者更高,WebView 類被更新了能夠支持打印 HTML 內容。這個類允許你加載本地 HTML 資源,或者從網頁下載頁面,創建一個打印工作,並把它傳遞給 Android 打印服務。

1.加載一個 HTML 文檔

打印 HTML 文檔從 WebView 包含加載 HTML 資源或者構建一個 HTML 文檔作為一個 String。本節描述如何構建一個HTML 字符串,加載到 WebView 並打印。

這個 View 對象作為一個活動布局的一部分。 然而,如果你的應用程序不使用 WebView,你可以創建一個類的實例專門作為打印目的。創建自定義打印視圖的主要步驟是。

1.創建一個 WebViewClient,開始一個打印工作,然後加載 HTML 資源
2.加載 HTML 資源到 WebView 對象。

下面的代碼示例,如何創建一個簡單的 WebViewClient 和動態創建HTML文檔。

private WebView mWebView;

private void doWebViewPrint() {
    // Create a WebView object specifically for printing
    WebView webView = new WebView(getActivity());
    webView.setWebViewClient(new WebViewClient() {

            public boolean shouldOverrideUrlLoading(WebView view, String url) {
                return false;
            }

            @Override
            public void 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 = "

Test Content

Testing, " + "testing, testing...

"; 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; }

注意:確保你生成一個打印工作是發生的在 onPageFinished() 方法中, WebViewClient 是在這之前被創建的。如果你沒有等到頁面加載完成後,打印輸出可能不完整或空白,或者完全可能會失敗。

注意:上面的示例代碼保留了一個實例 WebView 對象的實例,在打印作業被創建的時候,它不會被垃圾回收。 確保你做同樣的事情在自己實現中,否則,打印可能會失敗。

如果你想在頁面中打印一張圖表,圖表文件要放在你項目的 assest/ 目錄下,指定基本的 URL 作為 loadDataWithBaseURL() 方法的第一個參數。

webView.loadDataWithBaseURL("file:///android_asset/images/", htmlBody,
        "text/HTML", "UTF-8", null);

你也可以加載一個網頁並打印,把 loadDataWithBaseURL() 方法 替換成 loadUrl() 就可以了。

// 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.一個HTML文檔,其中包含CSS打印屬性,比如 landscape 屬性是不支持的。

5.你不能在HTML文檔中使用JavaScript來觸發打印。

注意:這個打印內容 WebView 對象包含在布局也可以打印一旦加載文檔。

2.創建一個打印作業

創建一個 WebView,加載了 HTML 內容,應用程序差不多完成了打印的一部分了。下一個步驟是訪問 PrintManager,創建一個打印適配器,最後,創建一個打印 的工作。下面的例子說明了如何執行這些步驟。

private void createWebPrintJob(WebView webView) {

    // Get a PrintManager instance
    PrintManager printManager = (PrintManager) getActivity()
            .getSystemService(Context.PRINT_SERVICE);

    // Get a print adapter instance
    PrintDocumentAdapter printAdapter = webView.createPrintDocumentAdapter();

    // Create a print job with name and adapter instance
    String jobName = getString(R.string.app_name) + " Document";
    PrintJob printJob = printManager.print(jobName, printAdapter,
            new PrintAttributes.Builder().build());

    // Save the job object for later status checking
    mPrintJobs.add(printJob);
}

這個例子中保存了一個 PrintJob 的實例在應用程序中,這不是必須的。你的應用程序可以使用這個對象的進程跟蹤打印工作的處理。這個方法是有用的,當你想監視的打印狀態的時候,你打印作業的完成,失敗,或用戶取消。創建一個應用內通知不需要的,因為打印框架會自動創建一個系統通知的打印作業。

打印自定義文件


對於一些應用程序,像畫圖 App,頁面布局 App 和其他 App,焦點在圖形輸出,創建一個漂亮的打印頁面是很重要的。在這樣的情況下,打印一張圖片或者是一個 HTML 文件是不夠的。這些類型的應用程序需要的打印輸出精確地控制一切,進入一個頁面,包括字體,文本流,分頁符,頁頭,頁腳和圖形元素。

創建一個完全自定義的打印輸出,你的應用程序要求投入更多的編程處理。你必須要構建這些組件,打印框架的通信,調整打印設置,畫出頁面的打印元素,管理多頁面打印。

節課向你展示了如何鏈接打印管理器,創建一個打印適配器和構建內容打印。

1.連接打印管理器

當你的引用程序直接管理打印過程,第一步接收打印請求從用戶連接 Android 打印框架,綁定 PrintManager 實例後。這個類允許你初始化打印工作,開始打印的生命周期。下面的代碼示例顯示了如何獲取打印管理器並開始打印過程。

private void doPrint() {
    // Get a PrintManager instance
    PrintManager printManager = (PrintManager) getActivity()
            .getSystemService(Context.PRINT_SERVICE);

    // Set job name, which will be displayed in the print queue
    String 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, new MyPrintDocumentAdapter(getActivity()),
            null); //
}

上面的示例代碼演示了如何命名一個打印作業並設置的一個實例 PrintDocumentAdapter 類處理打印生命周期的步驟。

2.創建一個打印適配器

打印適配器與Android打印框架進行交互,處理打印的過程。這個過程需要用戶選擇打印機和打印選項,在創建 一個文檔打印之前。這些選擇可以影響最終的輸出,用戶選擇打印機,打印機具有不同的輸出能力,不同的頁面大小,或不同頁面方向。隨著這些選擇,打印框架會詢問配器並生成打印文檔,為最終輸出做准備。一旦用戶按下打印按鈕,打印框架會取走最終的打印文檔,並將其傳遞到輸出的打印 Provider 。在印刷過程中,用戶可以選擇取消打印操作,所以你的打印適配器也必須監聽和處理取消的請求。

PrintDocumentAdapter 抽象類是設計成來處理打印的周期,有四個主要的回調方法。你必須實現這些方法,在你打印適配器中以響應打印框架的一些操作。

onStart() - -打印過程的開始時調用一次。如果你的應用程序有任何一次性任務做准備執行,比如要打印數據的快照,執行它們在這。不是必須實現的方法。

onLayout() - - 每次用戶更改打印設置,影響打印的輸出時被調用。如不同的頁面大小,頁面方向,給應用程序一個機會來計算的布局,要打印的頁面。至少,這個方法必須返回預計多少頁在打印文檔。

onWrite() - - 將打印的頁面渲染到要打印的文件中時被調用。這種方法可以每個onlayout()之後調用一次或以上。

onFinish() - - 打印過程結束時調用一次。如果你的應用程序有任何一次性銷毀任務執行,執行它們。不是必須實現的方法。

注意::這些適配器的方法是在應用程序的主線程中。 如果你期望的執行這些方法的實現需要大量的時間,實施在一個單獨的線程來執行。例如,你可以封裝布局或打印文檔編寫工作在 AsyncTask 對象中。

3.計算打印文件的信息

在一個實現的 PrintDocumentAdapter 類中,你的應用程序必須能夠指定創建的文檔類型和計算總的打印作業的頁面數量,給出打印頁面的大小的信息。 實現 onLayout() 方法在適配器中,使這些計算並提供預期的輸出信息打印作業在 PrintDocumentInfo 類,包括頁面數量和內容類型。下面的代碼示例顯示了一個基本的實現 onLayout() 方法在 PrintDocumentAdapter 中。

@Override
public void onLayout(PrintAttributes oldAttributes,
                     PrintAttributes newAttributes,
                     CancellationSignal cancellationSignal,
                     LayoutResultCallback callback,
                     Bundle metadata) {
    // Create a new PdfDocument with the requested page attributes
    mPdfDocument = new PrintedPdfDocument(getActivity(), newAttributes);

    // Respond to cancellation request
    if (cancellationSignal.isCancelled() ) {
        callback.onLayoutCancelled();
        return;
    }

    // Compute the expected number of printed pages
    int pages = computePageCount(newAttributes);

    if (pages > 0) {
        // Return print information to print framework
        PrintDocumentInfo info = new PrintDocumentInfo
                .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.");
    }
}

// 計算打印頁面數量
private int computePageCount(PrintAttributes printAttributes) {
    int itemsPerPage = 4; // default item count for portrait mode

    MediaSize pageSize = printAttributes.getMediaSize();
    if (!pageSize.isPortrait()) {
        // Six items per page in landscape orientation
        itemsPerPage = 6;
    }

    // Determine number of print items
    int printItemCount = getPrintItemCount();

    return (int) Math.ceil(printItemCount / itemsPerPage);
}

注意::布爾型參數的 onLayoutFinished() 方法顯示布局內容是否已經改變了自從上次請求後。正確設置這個參數允許打印框架來避免不必要的調用 onWrite() 方法,本質上緩存以前寫的打印文檔,提高性能。

4.寫一個打印文檔文件

是時候寫打印輸出到一個文件中了,Android 打印框架調用 onWrite() 方法在應用程序的 PrintDocumentAdapter 類。這個方法的參數指定哪個頁面被寫入到要使用的輸出文件。實現這個方法必須提供請求頁面的內容到一個多頁的PDF文檔文件。當這個過程完成時,回調onWriteFinished() 對象。

注意: Android打印框架可能回調 onWrite() 方法一次或多次,在每次調用 onLayout() 時。由於這個原因,設置 onLayoutFinished() 方法布爾參數為 false 時很重要的,當打印內容布局並沒有改變的時候。為了避免不必要的打印文檔的重寫。

下面的示例演示了這一過程使用的基本結構 PrintedPdfDocument 類來創建一個PDF文件。

@Override
public void onWrite(final PageRange[] pageRanges,
                    final ParcelFileDescriptor destination,
                    final CancellationSignal cancellationSignal,
                    final WriteResultCallback 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 cancellation
            if (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 file
    try {
        mPdfDocument.writeTo(new FileOutputStream(
                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);

    ...
}

創建文檔時一個耗時操作,應該放到子線程中去執行。

5.畫出PDF頁面內容

當應用程序打印時,你的應用程序必須生成PDF文檔並將其傳遞給 Android 打印框架打印。你可以使用任何PDF生成庫生成目的文件。這節課展示了如何使用 PrintedPdfDocument 類從你的內容生成PDF頁面。

PrintedPdfDocument 類使用一個 Canvas 對象元素畫一個PDF頁面,類似於畫一個Activity的布局。你可以畫打印頁面上的元素使用 Canvas 繪制方法。以下示例代碼演示了如何畫一些簡單的元素在PDF文檔頁面上使用這些方法。

private void 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 = new Paint();
    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, paint);
}
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved