使用PrintDocumentAdapter生成PDF右侧出现黑边问题求助
解决PrintDocumentAdapter打印ScrollView内容时PDF右侧出现黑边的问题
问题描述
使用PrintDocumentAdapter打印ScrollView内的界面内容时,生成的PDF文档右侧存在黑边,但实际界面并无该空白区域。调整canvas的x轴索引后问题依然存在。
原实现代码
public void printScrollViewContent() { PrintManager printManager = (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE); String jobName = getString(R.string.app_name) + " Document"; printManager.print(jobName, new PrintDocumentAdapter() { @Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { if (cancellationSignal.isCanceled()) { callback.onLayoutCancelled(); return; } // Get the dimensions of the scroll view int height = scrollView.getHeight(); // Get the total size of the content in the scroll view int totalHeight = scrollView.getChildAt(0).getHeight(); // Calculate the number of pages needed numberOfPages = (int) Math.ceil((double) totalHeight / height); Rect pageDimensions = new Rect(); scrollView.getDrawingRect(pageDimensions); // Prepare the PDF document layout PrintDocumentInfo.Builder builder = new PrintDocumentInfo.Builder("print_output.pdf"); builder.setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(numberOfPages); PrintDocumentInfo info = builder.build(); callback.onLayoutFinished(info, true); } @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { // Render content and write to PDF document PdfDocument pdfDocument = new PdfDocument(); for (int i = 0; i < numberOfPages; i++) { PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(scrollView.getWidth(), scrollView.getHeight(), i).create(); PdfDocument.Page page = pdfDocument.startPage(pageInfo); Canvas canvas = page.getCanvas(); // Calculate the portion of the content to be drawn for this page int start = i * canvas.getHeight(); int end = Math.min((i + 1) * canvas.getHeight(), scrollView.getChildAt(0).getHeight()); // Create bitmap of the portion of the scroll view content for this page Bitmap bitmap = Bitmap.createBitmap(scrollView.getWidth(), end - start, Bitmap.Config.ARGB_8888); Canvas contentCanvas = new Canvas(bitmap); contentCanvas.translate(0, -start); // Translate canvas to the appropriate position scrollView.getChildAt(0).draw(contentCanvas); // Draw the bitmap onto the canvas canvas.drawBitmap(bitmap, 0, 0, null); // Finish the page pdfDocument.finishPage(page); } try { // Write the PDF document to the output stream pdfDocument.writeTo(new FileOutputStream(destination.getFileDescriptor())); } catch (IOException e) { e.printStackTrace(); } finally { pdfDocument.close(); } callback.onWriteFinished(new PageRange[]{new PageRange(0, numberOfPages - 1)}); } }, null); }
问题根源
- 页面尺寸不匹配:原代码直接使用ScrollView的屏幕宽高创建PDF页面,但打印系统的纸张尺寸(如A4)宽高比与屏幕宽高比不一致,导致内容无法填满打印页面宽度,出现右侧空白/黑边。
- 内容宽度获取错误:使用
scrollView.getWidth()作为内容宽度,而实际内容宽度应为ScrollView子View的真实宽度(scrollView.getChildAt(0).getWidth()),当子View宽度超过ScrollView时会导致内容截断或空白。
修复后的代码
public void printScrollViewContent() { PrintManager printManager = (PrintManager) getContext().getSystemService(Context.PRINT_SERVICE); String jobName = getString(R.string.app_name) + " Document"; printManager.print(jobName, new PrintDocumentAdapter() { private int numberOfPages; private int contentWidth; private int contentTotalHeight; @Override public void onLayout(PrintAttributes oldAttributes, PrintAttributes newAttributes, CancellationSignal cancellationSignal, LayoutResultCallback callback, Bundle extras) { if (cancellationSignal.isCanceled()) { callback.onLayoutCancelled(); return; } // 获取ScrollView子View的真实内容尺寸 View contentView = scrollView.getChildAt(0); contentWidth = contentView.getWidth(); contentTotalHeight = contentView.getHeight(); // 将打印纸张尺寸转换为PDF使用的点单位(1英寸=72点) PrintAttributes.MediaSize mediaSize = newAttributes.getMediaSize(); int pageWidth = mediaSize.getWidthMils() * 72 / 1000; int pageHeight = mediaSize.getHeightMils() * 72 / 1000; // 计算缩放比例,让内容宽度完全适配打印页面宽度 float scale = (float) pageWidth / contentWidth; int scaledTotalHeight = (int) (contentTotalHeight * scale); // 计算需要的打印页数 numberOfPages = (int) Math.ceil((double) scaledTotalHeight / pageHeight); // 构建打印文档信息 PrintDocumentInfo info = new PrintDocumentInfo.Builder("print_output.pdf") .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT) .setPageCount(numberOfPages) .build(); callback.onLayoutFinished(info, true); } @Override public void onWrite(PageRange[] pages, ParcelFileDescriptor destination, CancellationSignal cancellationSignal, WriteResultCallback callback) { if (cancellationSignal.isCanceled()) { callback.onWriteCancelled(); return; } PdfDocument pdfDocument = new PdfDocument(); View contentView = scrollView.getChildAt(0); PrintAttributes.MediaSize mediaSize = new PrintAttributes.Builder().build().getMediaSize(); int pageWidth = mediaSize.getWidthMils() * 72 / 1000; int pageHeight = mediaSize.getHeightMils() * 72 / 1000; float scale = (float) pageWidth / contentWidth; for (int i = 0; i < numberOfPages; i++) { // 创建适配纸张尺寸的PDF页面 PdfDocument.PageInfo pageInfo = new PdfDocument.PageInfo.Builder(pageWidth, pageHeight, i + 1).create(); PdfDocument.Page page = pdfDocument.startPage(pageInfo); Canvas canvas = page.getCanvas(); // 计算当前页对应的内容起始位置(基于原始内容高度) int startY = (int) (i * pageHeight / scale); int endY = Math.min((int) ((i + 1) * pageHeight / scale), contentTotalHeight); int contentHeight = endY - startY; // 创建对应内容区域的Bitmap Bitmap bitmap = Bitmap.createBitmap(contentWidth, contentHeight, Bitmap.Config.ARGB_8888); Canvas contentCanvas = new Canvas(bitmap); contentCanvas.translate(0, -startY); // 偏移到当前页的内容位置 contentView.draw(contentCanvas); // 缩放Bitmap至打印页面宽度,避免右侧空白 canvas.save(); canvas.scale(scale, scale); canvas.drawBitmap(bitmap, 0, startY, null); canvas.restore(); pdfDocument.finishPage(page); } try { pdfDocument.writeTo(new FileOutputStream(destination.getFileDescriptor())); } catch (IOException e) { e.printStackTrace(); callback.onWriteFailed(e.getMessage()); return; } finally { pdfDocument.close(); } callback.onWriteFinished(new PageRange[]{new PageRange(0, numberOfPages - 1)}); } }, null); }
关键修改说明
- 适配打印纸张尺寸:获取打印属性中的纸张尺寸,转换为PDF标准的点单位,确保页面尺寸符合打印系统要求。
- 内容缩放适配:计算内容与打印页面的缩放比例,让内容宽度完全匹配打印页面宽度,消除右侧空白/黑边。
- 正确计算分页:基于缩放后的高度计算分页,保证每页内容完整。
- 真实内容尺寸:使用ScrollView子View的真实宽高作为内容尺寸,避免因ScrollView裁剪导致的内容错误。
内容的提问来源于stack exchange,提问作者user23515317
相关产品推荐
相关产品推荐

