Develop -- Training(十四) -- 打印内容
Posted 爱coding的卖油翁
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Develop -- Training(十四) -- 打印内容相关的知识,希望对你有一定的参考价值。
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 = "<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;
}
注意:确保你生成一个打印工作是发生的在 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);
}
以上是关于Develop -- Training(十四) -- 打印内容的主要内容,如果未能解决你的问题,请参考以下文章
Develop;Training(19)---设备连接无线网