使用iText7实现表格周围文本两端对齐时显示异常的问题
Fixing Poor Justified Text Wrapping Around Tables in iText7
我之前在iText7里折腾文本环绕表格+两端对齐的时候,也踩过一模一样的坑!左对齐看着好好的,一设成TextAlignment.JUSTIFIED就乱得没法看——要么是单词间距大得离谱,要么是文本和表格重叠,简直头大。下面分享几个我亲测有效的解决办法:
1. 确保用Float组件实现文本环绕
首先,很多人可能没注意:iText7里文本环绕表格必须通过Float容器来实现,直接加表格和段落只会上下排列。如果没正确用Float,两端对齐的布局计算会完全错乱。
示例代码:
// 创建要浮动的表格 Table table = new Table(1); table.addCell(new Cell().add(new Paragraph("Floating Table\nWith Multiple Lines"))); table.setWidth(UnitValue.createPercentValue(30)); // 设为页面宽度的30% // 把表格包装成Float元素,设置左浮动(文本绕右侧) Float floatTable = new Float(table); floatTable.setHorizontalAlignment(HorizontalAlignment.LEFT); document.add(floatTable);
2. 启用连字符优化两端对齐的排版
两端对齐最常见的问题就是单词间距过大——这是因为iText7默认不会自动给单词加连字符,为了撑满整行只能拉大间距。启用连字符可以让长单词换行时拆分,大幅改善排版效果。
示例代码:
// 初始化连字符配置(英文示例,其他语言需对应调整) HyphenationConfig hyphenationConfig = new HyphenationConfig("en", "US", 2, 2); // 创建两端对齐的段落并启用连字符 String longContent = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."; Paragraph justifiedPara = new Paragraph(longContent) .setAlignment(TextAlignment.JUSTIFIED) .setHyphenation(hyphenationConfig) .setMarginTop(0); // 去掉段落默认上边距,让文本紧贴表格 document.add(justifiedPara);
3. 自定义渲染器修正宽度计算(终极方案)
如果上面两步还是没解决问题,大概率是iText7默认的段落渲染器没有正确计算浮动表格占用的宽度,导致两端对齐时用了整个页面宽度来排版。这时候可以自定义一个段落渲染器,手动调整可用宽度:
public class WrappingJustifiedRenderer extends ParagraphRenderer { public WrappingJustifiedRenderer(Paragraph modelElement) { super(modelElement); } @Override public LayoutResult layout(LayoutContext layoutContext) { // 获取左浮动表格占用的宽度 float floatWidth = 0; LayoutArea originalArea = layoutContext.getArea(); for (IElement floatElem : originalArea.getFloatElements()) { if (floatElem instanceof Float) { floatWidth = ((Float) floatElem).getOccupiedArea().getBBox().getWidth(); break; } } // 调整布局区域,减去浮动表格的宽度 Rectangle adjustedBbox = new Rectangle( originalArea.getBBox().getX() + floatWidth, originalArea.getBBox().getY(), originalArea.getBBox().getWidth() - floatWidth, originalArea.getBBox().getHeight() ); LayoutArea adjustedArea = new LayoutArea(originalArea.getPageNumber(), adjustedBbox); LayoutContext adjustedContext = new LayoutContext(adjustedArea, layoutContext.getLayoutParams()); return super.layout(adjustedContext); } @Override public IRenderer getNextRenderer() { return new WrappingJustifiedRenderer((Paragraph) getModelElement()); } }
然后给段落设置这个自定义渲染器:
justifiedPara.setNextRenderer(new WrappingJustifiedRenderer(justifiedPara));
完整示例代码
把上面的步骤整合起来,完整的工作代码如下:
import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Cell; import com.itextpdf.layout.element.Float; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.element.Table; import com.itextpdf.layout.hyphenation.HyphenationConfig; import com.itextpdf.layout.layout.LayoutArea; import com.itextpdf.layout.layout.LayoutContext; import com.itextpdf.layout.layout.LayoutResult; import com.itextpdf.layout.renderer.IRenderer; import com.itextpdf.layout.renderer.ParagraphRenderer; import com.itextpdf.layout.properties.HorizontalAlignment; import com.itextpdf.layout.properties.TextAlignment; import com.itextpdf.kernel.geom.Rectangle; public class JustifiedTextWrapTable { public static void main(String[] args) throws Exception { PdfDocument pdfDoc = new PdfDocument(new PdfWriter("justified_wrap_table.pdf")); Document document = new Document(pdfDoc); // 1. 添加左浮动表格 Table table = new Table(1); table.addCell(new Cell().add(new Paragraph("Sample Floating Table\nLine 1\nLine 2"))); table.setWidth(UnitValue.createPercentValue(30)); Float floatTable = new Float(table); floatTable.setHorizontalAlignment(HorizontalAlignment.LEFT); document.add(floatTable); // 2. 创建两端对齐的文本,启用连字符 String longText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; HyphenationConfig hyphenationConfig = new HyphenationConfig("en", "US", 2, 2); Paragraph para = new Paragraph(longText) .setAlignment(TextAlignment.JUSTIFIED) .setHyphenation(hyphenationConfig) .setMarginTop(0); // 3. 应用自定义渲染器(如果需要) para.setNextRenderer(new WrappingJustifiedRenderer(para)); document.add(para); document.close(); } static class WrappingJustifiedRenderer extends ParagraphRenderer { public WrappingJustifiedRenderer(Paragraph modelElement) { super(modelElement); } @Override public LayoutResult layout(LayoutContext layoutContext) { float floatWidth = 0; LayoutArea originalArea = layoutContext.getArea(); for (IElement floatElem : originalArea.getFloatElements()) { if (floatElem instanceof Float) { floatWidth = ((Float) floatElem).getOccupiedArea().getBBox().getWidth(); break; } } Rectangle adjustedBbox = new Rectangle( originalArea.getBBox().getX() + floatWidth, originalArea.getBBox().getY(), originalArea.getBBox().getWidth() - floatWidth, originalArea.getBBox().getHeight() ); LayoutArea adjustedArea = new LayoutArea(originalArea.getPageNumber(), adjustedBbox); LayoutContext adjustedContext = new LayoutContext(adjustedArea, layoutContext.getLayoutParams()); return super.layout(adjustedContext); } @Override public IRenderer getNextRenderer() { return new WrappingJustifiedRenderer((Paragraph) getModelElement()); } } }
按照这个流程来,基本就能解决两端对齐时文本环绕表格的排版问题了。
内容的提问来源于stack exchange,提问作者aGe
相关产品推荐
相关产品推荐

