Android官方开发文档Training系列课程中文版:打印内容之自定义文档打印

原文地址:http://android.xsoftlab.net/training/printing/custom-docs.html

对于一些应用,比如绘图类APP,版面设计类APP以及其它APP,这些APP都关注图形的输出,有一个漂亮的打印页面是它们的关键特性。在这种情况下,就不单单是打印一张图片或者是HTML文档这么简单了。这些程序对于这种类型的打印需要对页面中每样事物的控制都特别的精细,包括字体、文本流、页面间距、页眉、页脚以及图形元素。

创建打印输出对于程序来说是完全自定义的,这需要更多设计上的投入,就像上面讨论的那样。你必须构建一些可以与打印框架交流的组件,并且还可以用来调整打印设置,绘制页面元素及管理多个页面的打印。

这节课展示了如何与打印管理者进行连接、创建打印适配器和构建打印内容。

连接打印管理者

当程序需要直接管理打印进程时,在收到用户的打印请求之后,第一步就是连接Android的打印框架,以及操作PrintManager类的实例。这个类允许你实例化一个打印工作并开始打印的生命过程。下面的代码展示了如何获得一个打印管理者和启动打印进程。

private void 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 documentprintManager.print(jobName, new MyPrintDocumentAdapter(getActivity()),null); //
}

上面的代码演示了如何命名一个打印工作并设置一个PrintDocumentAdapter的实例,这个对象可以处理打印过程的每一个步骤。打印适配器的实现会在下面的章节中讨论到。

Note: print()方法的最后一个参数需要一个PrintAttributes对象。你可以使用这个参数给打印框架提供一些提示及给原先的打印周期预先设置一些选项,这可以改进用户体验。你还可以使用这个参数来设置一些选项,这些选项更适用于内容的打印,比如当打印照片的时候可以设置打印的方向为照片本身的方向。

创建打印适配器

打印适配器会与Android的打印框架相连接,并会处理打印过程的每一个步骤。这个过程要求用户在创建文档打印之前选择打印机及相关的打印选项。这些过程会影响最终的输出结果,就像用户选择了不同打印能力,不同的页面尺寸,不同的页面方向一样。随着这些选项的设置,打印框架会要求适配器展示并生成一个打印文稿,为最终的打印做准备。一旦用户按下了打印按钮,打印框架会拿到最终的打印文档然后交付给打印提供者以便打印。在打印的过程中,用户可以选择取消打印行为,所以打印适配器必须监听并响应取消请求。

抽象类PrintDocumentAdapter被设计为用来处理打印过程的生命周期,它拥有4个主要的回调方法。你必须在打印适配器中实现这些方法,以便可以与打印框架进行适当的交互:

  • onStart() - 会在打印进程开始的时候调用一次,如果应用对任务有任何的单次预处理任务,比如获取要打印的数据段,就可以在这里执行。实现这个方法并不是必须要求的。
  • onLayout() - 会在用户每次更改打印设置的时候调用一次,这会影响到最终的输出结果,比如不同的页面尺寸,或者页面方向,提供给程序一个机会来估算页面的版面。在最低限度下,这个方法必须返回将要打印的文档有多少页。
  • onWrite() - 该方法被用来将要打印的页面作用到一个文件中,然后再被打印。这个方法可能会在onLayout()方法每次调用之后被调用一次或者多次,
  • onFinish() - 该方法会在打印过程结束的时候调用一次。如果程序对打印任务需要任何的销毁工作,那可以在这里执行。这个方法不是必须要求被实现的。

下面的章节会描述如何实现layout和write方法,这两个方法实现了打印适配器的决定性功能。

Note: 适配器方法会在程序的主线程中被调用。如果你认为执行这些方法会消耗大量时间的话,那么可以在单独的线程中实现它们。举个例子,你可以将layout或者打印文档的writing工作放入单独的AsyncTask对象中。

计算文档信息

在PrintDocumentAdapter的实现中,程序必须指定文档的类型,它还需要创建并计算打印工作的总页数,获得被打印页的尺寸信息。onLayout()方法应该进行这些计算并且将要输出的文档信息放入一个PrintDocumentInfo对象中,包括页面数量以及内容类型。下面的代码展示onLayout()方法的最基础实现:

@Override
public void onLayout(PrintAttributes oldAttributes,PrintAttributes newAttributes,CancellationSignal cancellationSignal,LayoutResultCallback callback,Bundle metadata) {// Create a new PdfDocument with the requested page attributesmPdfDocument = new PrintedPdfDocument(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 = new PrintDocumentInfo.Builder("print_output.pdf").setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT).setPageCount(pages);.build();// Content layout reflow is completecallback.onLayoutFinished(info, true);} else {// Otherwise report an error to the print frameworkcallback.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 modeMediaSize pageSize = printAttributes.getMediaSize();if (!pageSize.isPortrait()) {// Six items per page in landscape orientationitemsPerPage = 6;}// Determine number of print itemsint printItemCount = getPrintItemCount();return (int) Math.ceil(printItemCount / itemsPerPage);
}

写入打印文档文件

当写入打印结果到文件中时,Android打印框架会调用onWrite()方法。这个方法的参数指明了哪一页需要被写入以及被使用到的输出文件。你的实现必须将每个请求内容页渲染到一个多页的PDF文档文件中。这个过程完成以后,你需要调用回调对象的onWriteFinished()方法。

Note: 由于Android打印框架可能会在每次调用onLayout()方法之后调用若干次onWrite()方法,所以在打印页面并没有发生实质上的改变时设置onLayoutFinished()方法的布尔参数为false是很重要的,这样可以避免对打印文档进行不必要的重复写入。

Note: onLayoutFinished()方法的布尔参数指示了从最后一次请求开始版面的内容是否有实质上的改变。适当的设置这个参数可以允许打印框架避免对onWrite()方法进行不必要的调用,实质上会缓存原先的书面打印文档并改善性能。

下面简要演示了使用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 cancellationif (cancellationSignal.isCancelled()) {callback.onWriteCancelled();mPdfDocument.close();mPdfDocument = null;return;}// Draw page content for printingdrawPage(page);// Rendering is complete, so page can be finalized.mPdfDocument.finishPage(page);}}// Write PDF document to filetry {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 completecallback.onWriteFinished(writtenPages);...
}

这个示例将PDF页的内容委派给了drawPage()方法,这会在下面的章节中讨论。

和layout一样,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页面时,元素由一些点来指定位置,这个点的大小是英寸的72分之一。要确保使用这个测量单位来指明元素的尺寸。对于绘制元素的定位,坐标系统会从页面的左上角0,0点开始。

Tip: 虽然Canvas对象允许你将打印元素放置到PDF文档的边上,但很多打印机并没有能力可以将边上的元素打印到纸上去。要确保在使用这个类构建打印文档时要保留一定的页面边距。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/479146.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 547. 朋友圈(图的遍历BFS DFS)

文章目录1. 题目2. 解题2.1 BFS 广度优先2.2 DFS 深度优先1. 题目 问有几个连通网络 2. 解题 2.1 BFS 广度优先 参考图的数据结构 class Solution { public:int findCircleNum(vector<vector<int>>& M) {int n M.size(), groups 0, i;bool visited[n] …

开源开放 | 《大词林》开源 75 万核心实体和围绕核心实体的细粒度概念、关系列表...

1《大词林》简介《大词林》(http://101.200.120.155/)是由哈尔滨工业大学社会计算与信息检索研究中心推出&#xff0c;由我中心秦兵教授和刘铭副教授主持开发&#xff0c;是一个自动构建的大规模开放域中文知识库。自2014年11月推出第一版《大词林》&#xff0c;《大词林》共经…

推荐几个不错的CUDA入门教程(非广告)

文 | godweiyang最近因为项目需要&#xff0c;入坑了CUDA&#xff0c;又要开始写很久没碰的C了。对于CUDA编程以及它所需要的GPU、计算机组成、操作系统等基础知识&#xff0c;我基本上都忘光了&#xff0c;因此也翻了不少教程。这里简单整理一下&#xff0c;给同样有入门需求的…

logging.getLogger(logger)

https://www.cnblogs.com/bjdxy/archive/2012/12/03/2799322.html logging模块学习笔记&#xff1a;logger 对象、日志等级 logger&#xff1a;日志对象&#xff0c;logging模块中最基础的对象&#xff0c;用logging.getLogger(name)方法进行初始化&#xff0c;name可以不填。通…

Android官方开发文档Training系列课程中文版:高效显示位图之加载大位图

原文地址&#xff1a;http://android.xsoftlab.net/training/displaying-bitmaps/index.html 引言 学习如何使用一种常规的手段来处理及加载Bitmap对象&#xff0c;这种方式除了使用户界面是可响应的之外&#xff0c;还会避免超出内存的限制。如果你不小心点的话&#xff0c;…

美团DB数据同步到数据仓库的架构与实践

背景 在数据仓库建模中&#xff0c;未经任何加工处理的原始业务层数据&#xff0c;我们称之为ODS(Operational Data Store)数据。在互联网企业中&#xff0c;常见的ODS数据有业务日志数据&#xff08;Log&#xff09;和业务DB数据&#xff08;DB&#xff09;两类。对于业务DB数…

论文浅尝 | AAAI2020 - 基于生成对抗的知识图谱零样本关系学习

论文笔记整理&#xff1a;耿玉霞&#xff0c;浙江大学直博生。研究方向&#xff1a;知识图谱&#xff0c;零样本学习等。来源&#xff1a;AAAI2020论文链接&#xff1a;https://arxiv.org/pdf/2001.02332.pdf本文是发表在AAAI2020上的一篇基于生成对抗网络进行知识图谱零样本关…

LeetCode 1184. 公交站间的距离

1. 题目 环形公交路线上有 n 个站&#xff0c;按次序从 0 到 n - 1 进行编号。我们已知每一对相邻公交站之间的距离&#xff0c;distance[i] 表示编号为 i 的车站和编号为 (i 1) % n 的车站之间的距离。 环线上的公交车都可以按顺时针和逆时针的方向行驶。 返回乘客从出发点…

【python】详解类class的继承、__init__初始化、super方法

原文链接; https://blog.csdn.net/brucewong0516/article/details/79121179?utm_mediumdistribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_sourcedistribute.pc_relevant_t0.none-task-blog-BlogCommendFromBaidu-1.control 通过之前…

追剧计划第三弹!UC Berkeley出品,全栈深度学习!

关注卖萌屋比较早的小伙伴&#xff0c;大概还记得2020年初时我们组织的斯坦福大学CS224N自然语言处理公开课追剧计划&#xff0c;以及后来的斯坦福大学CS520知识图谱公开课追剧活动。尽管活动已经结束很长一段时间&#xff0c;但是仍然有小伙伴后台问“什么时候开始下一波追剧哇…

Android官方开发文档Training系列课程中文版:高效显示位图之在非UI线程中处理图片

原文地址&#xff1a;http://android.xsoftlab.net/training/displaying-bitmaps/process-bitmap.html 我们在上节课Load Large Bitmaps Efficiently中讨论了BitmapFactory.decode*方法&#xff0c;说到了不应该在UI线程中执行读取数据的过程&#xff0c;尤其是从磁盘或者网络…

美团外卖iOS App冷启动治理

一、背景 冷启动时长是App性能的重要指标&#xff0c;作为用户体验的第一道“门”&#xff0c;直接决定着用户对App的第一印象。美团外卖iOS客户端从2013年11月开始&#xff0c;历经几十个版本的迭代开发&#xff0c;产品形态不断完善&#xff0c;业务功能日趋复杂&#xff1b;…

LeetCode 538. 把二叉搜索树转换为累加树(逆中序 根右左)

文章目录1. 题目2. 逆中序&#xff08;根右左&#xff0c;降序循环遍历&#xff09;1. 题目 给定一个二叉搜索树&#xff08;Binary Search Tree&#xff09;&#xff0c;把它转换成为累加树&#xff08;Greater Tree)&#xff0c;使得每个节点的值是原来的节点值加上所有大于…

应用实践 | 电商应用——一种基于强化学习的特定规则学习模型

本文转载自公众号&#xff1a;浙大KG。作者&#xff1a;汪寒&#xff0c;浙江大学硕士&#xff0c;主要研究方向为知识图谱和自然语言处理。应用场景在电商实际应用中&#xff0c;每个商品都会被挂载到若干个场景&#xff0c;以图结构中的节点形式存在。商品由结构化信息表示&a…

20W奖金+实习机会:阿里巴巴达摩院最新时间序列赛事来了!

Datawhale赛事 赛事&#xff1a;2021“AI Earth”人工智能挑战赛2021“AI Earth”人工智能创新挑战赛&#xff0c;由阿里巴巴达摩院联合南京信息工程大学、国家气候中心、国家海洋环境预报中心、安徽省气象局共同创办。大赛以“AI助力精准气象和海洋预测”为主题&#xff0c;聚…

关于python中带下划线的变量和函数 的意义,class类带一个下划线和带两个下划线的定义

总结:变量:1. 前带_的变量: 标明是一个私有变量, 只用于标明, 外部类还是可以访问到这个变量2. 前带两个_ ,后带两个_ 的变量: 标明是内置变量,3. 大写加下划线的变量: 标明是 不会发生改变的全局变量函数:1. 前带_的变量: 标明是一个私有函数, 只用于标明,2. 前带两个_…

Android官方开发文档Training系列课程中文版:高效显示位图之位图缓存

原文地址&#xff1a;http://android.xsoftlab.net/training/displaying-bitmaps/cache-bitmap.html 往UI界面中加载单张图片的过程是很简单的&#xff0c;然而如果需要在某个时刻同时加载大量的图片&#xff0c;那么这事情就有些复杂了。在很多情况下&#xff0c;比如使用了L…

论文浅尝 | ICLR2020 - 基于组合的多关系图卷积网络

论文笔记整理&#xff1a;吴锐&#xff0c;东南大学计算机学院硕士。来源&#xff1a;ICLR 2020链接&#xff1a;https://arxiv.org/pdf/1911.03082.pdf动机目前针对于GCN的研究大多数都关注在学习无向图的结点表示上&#xff0c;然而我们在研究中更常见的通常是多关系图&#…

Hades:移动端静态分析框架

只有通过别人的眼睛&#xff0c;才能真正地了解自己 ——《云图》 背景 作为全球最大的互联网 生活服务平台&#xff0c;美团点评近年来在业务上取得了飞速的发展。为支持业务的快速发展&#xff0c;移动研发团队规模也逐渐从零星的小作坊式运营&#xff0c;演变为千人级研发军…

GitHub超级火!任意爬取,超全开源爬虫工具箱

文 | 程序员GitHub最近国内一位开发者在 GitHub 上开源了个集众多数据源于一身的爬虫工具箱——InfoSpider&#xff0c;一不小心就火了&#xff01;&#xff01;&#xff01;有多火呢&#xff1f;开源没几天就登上GitHub周榜第四&#xff0c;标星1.3K&#xff0c;累计分支 172 …