亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

【Android Developers Training】 54. 打印自定

系統 1876 0

注:本文翻譯自Google官方的Android Developers Training文檔,譯者技術一般,由于喜愛安卓而產生了翻譯的念頭,純屬個人興趣愛好。

原文鏈接: http://developer.android.com/training/printing/custom-docs.html


對一些應用,比如繪圖應用,頁面布局應用和其它一些聚焦于圖像輸出的應用,創建美麗的打印頁面是它的可信功能。在這種情況下,僅僅打印一副圖片或一個HTML文檔就不夠了。這種類型應用的打印輸出需要精確地控制每個進入頁面的東西,包括字體,文本流,分頁符,頁眉,頁腳和一些圖像元素。

創建完全由你自定義的打印輸出需要投入比之前討論的方法更多的編程精力。你必須構建可以和打印架構相互通信的組件,調整打印選項,繪制頁面元素并管理多個頁面的打印。

這節課將向你展示如何連接打印管理器,創建一個打印適配器并構建要打印的內容。


一). 連接打印管理器

當你的應用直接管理打印進程,在收到來自用戶的打印請求后,第一步要做的是連接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 類的實例,它處理打印生命周期的每一步。打印適配器的實現會在下一節中進行討論。

Note:

print() 方法的最后一個參數接收一個 PrintAttributes 對象。你可以使用這個參數來提供對于打印框架的提示,以及基于前一個打印周期的預設,從而改善用戶體驗。你也可以使用這個參數來設置一些更符合被打印對象的一些設定,比如當打印一副照片時,設置打印的方向與照片方向一致。


二). 創建一個打印適配器

一個打印適配器和Android打印框架交互并處理打印過程的每一步。這個過程需要用戶在創建打印的文檔前選擇打印器和打印選項。這些選項可以影響最終的輸出,因為用戶選擇的打印機可能會有不同的打印的能力,不同的頁面尺寸或不同的頁面方向。隨著這些選項配置好了,這個打印框架會詢問你的你的適配器去布局和生成一個打印文檔,作為最終打印的前期準備。一旦用戶點擊了打印按鈕,這個框架接收最終的打印文檔,并將將它傳遞給一個打印提供程序來打印輸出。在打印過程中,用戶可以選擇取消打印的行為,所以你的打印適配器必須監聽并響應一個取消請求。

PrintDocumentAdapter 抽象類被設計用來處理打印的生命周期,它有四個主要的回調函數。你必須在你的打印適配器中實現這些方法,以此來恰當地和打印框架交互:

  • onStart() ?- 一旦打印的進程開始了就被調用。如果你的應用有任何一次性的準備任務要執行,比如獲取一個要打印數據的快照,那么將它們在此處執行。在你的適配器中,這個回調函數不是必須實現的。
  • onLayout() ?- 每次一個用戶改變了一個打印設置并印象了打印的輸出時調用,比如改變了頁面的尺寸,或者頁面的方向,給你的應用一個機會去重新計算要打印頁面的布局。這個方法必須返回打印文檔包含多少頁面。
  • onWrite() ?- 調用它以此將打印頁面交付給一個要打印的文件。這個方法可以在被 onLayout() 調用后調用一次或多次。
  • onFinish() ?- 一旦打印進程結束后被調用。如果你的應用有任何一次性銷毀任務要執行,在這里執行。這個回調函數不是必須實現的。

下面的部分將介紹如何實現布局和寫方法,這兩個方法是一個打印適配器的核心功能。

Note:

這些適配器的回調函數會在你的主線程上被調用。如果你的這些方法的實現需要花費大量的時間,那么應該在一個另外的線程里執行。例如:你可以將布局或者寫入打印文檔的操作封裝在一個 AsyncTask 對象中。

計算打印文檔信息

在一個 PrintDocumentAdapter 類的實現中,你的應用必須指定所創建文檔的類型并計算所有打印任務所需要的頁數,提供被打印頁面的尺寸信息。在適配器中 onLayout() 方法的實現會執行這些計算,并提供打印任務輸出的信息,這些信息在一個 PrintDocumentInfo 類中,包括頁數和內容類型。下面的例子展示了 PrintDocumentAdapter onLayout() 方法的基本實現:

      
        @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."
      
        );

    }

}
      
    

onLayout() 方法的執行結果又三種:完成,取消或失敗(計算布局無法順利完成時會失敗)。你必須通過調用 PrintDocumentAdapter.LayoutResultCallback 對象中的適當方法來指明這些結果中的一個。

Note:

onLayoutFinished() 方法的布爾參數明確了這個布局內容是否是否和上一次請求相比確實改變了。恰當地設定了這個參數將避免打印框架不必要的調用 onWrite() 方法,緩存之前的打印文檔,并提升性能。

onLayout() 的主要工作是計算打印文檔的頁數,作為交給打印機的參數。如何計算頁數高度依賴于你的應用時如何布局打印頁面的。下面的代碼展示了頁數是如何根據打印方向確定的:

      
        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);

}
      
    

將打印文檔寫入文件

當需要將打印輸出寫入一個文件時,Android打印框架會調用你的應用 PrintDocumentAdapter 類的 onWrite() 方法。這個方法的參數指定了哪一頁要被打印以及要使用的輸出文件。你的這個方法的實現必須將每一個請求也的內容交付給一個多頁PDF文檔文件。當這個過程結束以后,你需要調用回調對象的 onWriteFinished() 方法。

Note:

Android打印框架可能會在每次調用 onLayout() 后,調用 onWrite() 方法一次甚至更多次。在這節課當中,有一件非常重要的事情是當打印內容的布局沒有變化時,需要將 onLayoutFinished() 方法的布爾參數設置為“ false ”,以此避免不必要的重寫打印文檔的操作。

Note:

onLayoutFinished() 方法的布爾參數指出這個布局內容是否和上一次請求相比發生了實際的變化。恰當地設置這個參數可以讓打印框架避免不必要的調用 onLayout() 方法,緩存過去寫入的打印文檔并提升性能。

下面的代碼展示了使用 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);



    ...

}
      
    

這個代碼中將PDF頁面遞交給了 drawPage() 方法,這個方法會在下一部分介紹。

就布局而言, onWrite() 方法的執行可以有三種結果:完成,取消或者失敗(內容無法被寫入)。 你必須通過調用 PrintDocumentAdapter.WriteResultCallback 對象中的適當方法來指明這些結果中的一個。

Note:

遞交一個打印的文檔可以是一個和大量資源相關的操作。為了避免阻塞應用的主UI線程,你應該考慮將頁面的遞交和寫操作在另一個線程中執行,比如在 AsyncTask 中。關于更多異步任務線程的知識,可以閱讀: Processes and Threads


三). 繪制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);

}
      
    

當使用 Canvas 在一個PDF頁面上繪圖時,元素通過單位“ 點(point) ”來指定大小,它是七十二分之一英寸大小。確保你使用這個測量單位來指定頁面上的元素大小。在定位繪制的元素時,坐標系的原點(即(0,0))在頁面的最左上角。

Tip:

雖然 Canvas 對象允許你將打印元素放置在一個PDF文檔的邊緣,但許多打印機并不能再紙張邊緣打印。所以當你使用這個類構建一個打印文檔時,確保你考慮了那些無法打印的邊緣區域。

【Android Developers Training】 54. 打印自定義文檔


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 欧美视频三区 | 日本免费三区 | 四虎永久在线精品视频播放 | 五月一区二区久久综合天堂 | 亚洲欧洲尹人香蕉综合 | 老司机福利深夜亚洲入口 | 久久视频在线免费观看 | 日韩精品一区二区三区中文字幕 | a毛片毛费观看 | 日本欧美一区二区三区在线观看 | 欧美精品亚洲网站 | 奇米激情 | 久久99精品久久久久子伦小说 | 国产一区日韩二区欧美三 | 国内精品久久久久影院日本 | 99久久精品免费看国产一区二区 | 99精品视频在线 | 亚洲精品成人a在线观看 | 欧美乱一级在线观看 | 模特精品一区二区三区 | 久久日韩精品激情 | 日韩欧美伊人久久大香线蕉 | 一区二区三区精品视频 | 色婷婷久| 99热久久国产精品这 | 天天夜夜人人 | 色综合网站国产麻豆 | 国产xxx视频 | 北岛玲日韩精品一区二区三区 | 亚洲视频成人 | 草逼网站| 欧美精品成人一区二区视频一 | 久久精品国产99精品最新 | 久久免费视频网 | 中文字幕一区在线观看 | 欧美久草 | 老师在办公室被躁到白浆 | 国产日韩欧美精品一区二区三区 | 激情四房 | 尹人香蕉网 | 日韩精品亚洲精品485页 |