Android Studio基于iTextG实现ListView内容多页PDF生成问题
Fixing iTextG PDF Pagination for Long ListView Content on Android
Got it, let's tackle this truncation issue head-on. I’ve worked through similar scenarios where ListView content spills beyond a single PDF page, so here’s a practical, step-by-step solution that handles automatic pagination seamlessly.
Core Idea
Instead of trying to capture the entire ListView as one giant bitmap (which causes truncation), we’ll:
- Calculate the exact height of each ListView item (even the invisible ones)
- Track how much space we’ve used on the current PDF page
- Automatically start a new page when the current item won’t fit in the remaining space
- Draw each item (and dividers) to the PDF page by page
Step 1: Calculate Total & Individual Item Heights
First, we need a helper method to measure the height of every ListView item—critical because off-screen items haven’t been laid out yet.
private int calculateListViewItemHeight(ListView listView, int position) { ListAdapter adapter = listView.getAdapter(); if (adapter == null || position >= adapter.getCount()) return 0; // Inflate and measure the item view View listItem = adapter.getView(position, null, listView); listItem.measure( View.MeasureSpec.makeMeasureSpec(listView.getWidth(), View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) ); return listItem.getMeasuredHeight(); } // Optional: Calculate total height if you want to pre-determine page count private int calculateTotalListViewHeight(ListView listView) { ListAdapter adapter = listView.getAdapter(); if (adapter == null) return 0; int totalHeight = 0; for (int i = 0; i < adapter.getCount(); i++) { totalHeight += calculateListViewItemHeight(listView, i); totalHeight += listView.getDividerHeight(); // Add divider height } totalHeight -= listView.getDividerHeight(); // Remove extra divider at end return totalHeight; }
Step 2: Generate Paginated PDF
Here’s the core logic that handles pagination. We’ll iterate through each ListView item, check if it fits on the current page, and create new pages as needed.
public void generatePaginatedPdf(Context context, ListView listView, String outputFilePath) throws IOException, DocumentException { // Initialize PDF document with A4 page size Document document = new Document(PageSize.A4); PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(outputFilePath)); document.open(); // Define page margins (convert mm to points: 1mm = 2.83465pt) final float marginLeft = 20 * 2.83465f; final float marginRight = 20 * 2.83465f; final float marginTop = 20 * 2.83465f; final float marginBottom = 20 * 2.83465f; // Calculate usable page dimensions float usablePageWidth = PageSize.A4.getWidth() - marginLeft - marginRight; float usablePageHeight = PageSize.A4.getHeight() - marginTop - marginBottom; ListAdapter adapter = listView.getAdapter(); if (adapter == null) { document.close(); return; } float currentPageUsedHeight = marginTop; // Track space used on current page PdfContentByte canvas = writer.getDirectContent(); for (int itemIndex = 0; itemIndex < adapter.getCount(); itemIndex++) { // Get and measure the current ListView item View listItem = adapter.getView(itemIndex, null, listView); listItem.measure( View.MeasureSpec.makeMeasureSpec((int) usablePageWidth, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED) ); listItem.layout(0, 0, listItem.getMeasuredWidth(), listItem.getMeasuredHeight()); // Convert View to Bitmap listItem.setDrawingCacheEnabled(true); Bitmap itemBitmap = Bitmap.createBitmap(listItem.getDrawingCache()); listItem.setDrawingCacheEnabled(false); // Calculate scaled item height (maintain aspect ratio) float scaledItemHeight = itemBitmap.getHeight() * (usablePageWidth / itemBitmap.getWidth()); // Check if item fits on current page if (currentPageUsedHeight + scaledItemHeight > PageSize.A4.getHeight() - marginBottom) { // No space left—start new page document.newPage(); currentPageUsedHeight = marginTop; } // Draw the item bitmap to PDF Image itemImage = Image.getInstance(itemBitmap, null); itemImage.setAbsolutePosition( marginLeft, PageSize.A4.getHeight() - currentPageUsedHeight - scaledItemHeight ); itemImage.scaleToFit(usablePageWidth, scaledItemHeight); document.add(itemImage); // Update used height (add item height + divider if not last item) currentPageUsedHeight += scaledItemHeight; if (itemIndex != adapter.getCount() - 1) { // Scale divider height to match PDF page width float scaledDividerHeight = listView.getDividerHeight() * (usablePageWidth / listView.getWidth()); currentPageUsedHeight += scaledDividerHeight; } // Clean up bitmap to avoid memory leaks if (!itemBitmap.isRecycled()) { itemBitmap.recycle(); } } document.close(); }
Key Notes & Troubleshooting
- Async Content Handling: If your ListView items contain images loaded asynchronously, make sure all content is fully loaded before generating the PDF (use a callback or wait for loading to complete).
- Theme Consistency: When inflating ListView items, ensure the Context uses the correct theme so the item styling matches what’s displayed on screen.
- Memory Management: Recycling bitmaps is crucial—large ListViews can cause OOM if bitmaps aren’t properly cleaned up.
- Custom Item Heights: This solution works even if your ListView has variable-height items, since we measure each item individually.
内容的提问来源于stack exchange,提问作者Olana Kenea
相关产品推荐
相关产品推荐

