打印自定义文档

    对于有些应用,比如绘图应用,页面布局应用和其它一些关注于图像输出的应用,创造出精美的打印页面将是它的核心功能。在这种情况下,仅仅打印一幅图片或一个HTML文档就不够了。这类应用的打印输出需要精确地控制每一个会在页面中显示的对象,包括字体,文本流,分页符,页眉,页脚和一些图像元素等等。

    想要创建一个完全自定义的打印文档,需要投入比之前讨论的方法更多的编程精力。我们必须构建可以和打印框架相互通信的组件,调整打印参数,绘制页面元素并管理多个页面的打印。

    这节课将展示如何连接打印管理器,创建一个打印适配器以及如何构建出需要打印的内容。

    当我们的应用直接管理打印进程时,在收到来自用户的打印请求后,第一步要做的是连接Android打印框架并获取一个PrintManager类的实例。该类允许我们初始化一个打印任务并开始打印任务的生命周期。下面的代码展示了如何获得打印管理器并开始打印进程。

    上面的代码展示了如何命名一个打印任务以及如何设置一个类的实例,它负责处理打印生命周期的每一步。打印适配器的实现会在下一节中进行讨论。

    Note:print()方法的最后一个参数接收一个对象。我们可以使用这个参数向打印框架进行一些打印设置,以及基于前一个打印周期的预设,从而改善用户体验。我们也可以使用这个参数对打印内容进行一些更符合实际情况的设置,比如当打印一幅照片时,设置打印的方向与照片方向一致。

    打印适配器负责与Android打印框架交互并处理打印过程的每一步。这个过程需要用户在创建打印文档前选择打印机和打印选项。由于用户可以选择不同性能的打印机,不同的页面尺寸或不同的页面方向,因此这些选项可能会影响最终的打印效果。当这些选项配置好之后,打印框架会寻求适配器进行布局并生成一个打印文档,以此作为打印的前期准备。一旦用户点击了打印按钮,框架会将最终的打印文档传递给Print Provider进行打印输出。在打印过程中,用户可以选择取消打印,所以打印适配器必须监听并响应取消打印的请求。

    • onLayout():每当用户改变了影响打印输出的设置时(比如改变了页面的尺寸,或者页面的方向)该函数将会被调用,以此给我们的应用一个机会去重新计算打印页面的布局。另外,该方法必须返回打印文档包含多少页面。
    • :该方法调用后,会将打印页面渲染成一个待打印的文件。该方法可以在onLayout()方法被调用后调用一次或多次。

    下面将介绍如何实现以及onWrite()方法,他们是打印适配器的核心功能。

    在实现类时,我们的应用必须能够指定出所创建文档的类型,计算出打印任务所需要打印的总页数,并提供打印页面的尺寸信息。在实现适配器的onLayout()方法时,我们执行这些计算,并提供与理想的输出相关的一些信息,这些信息可以在类中获取,包括页数和内容类型。下面的例子展示了PrintDocumentAdapter中方法的基本实现:

    onLayout()方法的执行结果有三种:完成,取消或失败(计算布局无法顺利完成时会失败)。我们必须通过调用对象中的适当方法来指出这些结果中的一个。

    Note:onLayoutFinished()方法的布尔类型参数明确了这个布局内容是否和上一次打印请求相比发生了改变。恰当地设定了这个参数将避免打印框架不必要地调用方法,缓存之前的打印文档,提升执行性能。

    onLayout()的主要任务是计算打印文档的页数,并将它作为打印参数交给打印机。如何计算页数则高度依赖于应用是如何对打印页面进行布局的。下面的代码展示了页数是如何根据打印方向确定的:

    将打印文档写入文件

    当需要将打印内容输出到一个文件时,Android打印框架会调用PrintDocumentAdapter类的方法。这个方法的参数指定了哪些页面要被写入以及要使用的输出文件。该方法的实现必须将每一个请求页的内容渲染成一个含有多个页面的PDF文件。当这个过程结束以后,你需要调用callback对象的onWriteFinished()方法。

    下面的代码展示了使用类创建了PDF文件的基本原理:

    代码中将PDF页面递交给了drawPage()方法,这个方法会在下一部分介绍。

    就布局而言,onWrite()方法的执行可以有三种结果:完成,取消或者失败(内容无法被写入)。我们必须通过调用对象中的适当方法来指明这些结果中的一个。

    Note:渲染打印文档是一个可能耗费大量资源的操作。为了避免阻塞应用的主UI线程,我们应该考虑将页面的渲染和写操作放在另一个线程中执行,比如在AsyncTask中执行。关于更多异步任务线程的知识,可以阅读:。

    当我们的应用进行打印时,应用必须生成一个PDF文档并将它传递给Android打印框架以进行打印。我们可以使用任何PDF生成库来协助完成这个操作。本节将展示如何使用PrintedPdfDocument类将打印内容生成为PDF页面。

    类使用一个Canvas对象来在PDF页面上绘制元素,这一点和在activity布局上进行绘制很类似。我们可以在打印页面上使用类提供的相关绘图方法绘制页面元素。下面的代码展示了如何使用这些方法在PDF页面上绘制一些简单的元素: