失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > iText7高级教程之构建基础块——4.使用AbstractElement对象(part 1)

iText7高级教程之构建基础块——4.使用AbstractElement对象(part 1)

时间:2022-10-02 08:16:23

相关推荐

iText7高级教程之构建基础块——4.使用AbstractElement对象(part 1)

作者:CuteXiaoKe

微信公众号:CuteXiaoKe

在之前的章节中,我们讨论了实现AbstractElement类的5个类。在章节2中,我们讨论了AreaBreak类。在章节3中我们讨论了实现ILeafElement类的4个类——TabLinkTextImage类。在这章节,我们会着重于其他一系列实现AbstractElement的类。如用于分组元素的Div类和用于在元素之间划线的LineSeparator。我们在之前的章节中已经多次使用过Paragraph类,但是在本章中我们将会重新讨论它。最后我们将讨论List类和ListItem类,而TableCell类将会在下一章节中讲述。

1. 使用Div类分组元素

Div类是BlockElement类的实现,可以用来分组不同的元素。在图4.1中,我们可以看到Jekyll and Hyde系列电影的概览。其中每个条目包含最多三种元素:

一个Paragraph显示电影的标题;一个Paragraph显示导演、国家和年份;一个Image显示电影海报(如果有的话);

我们将这个三个元素组合在一个Div中,并为这个Div定义了左边框、左填充和下边距。

图4.1 在一个div中组合元素

整体代码如下:

public void createPdf(String dest) throws IOException {PdfDocument pdf = new PdfDocument(new PdfWriter(dest));Document document = new Document(pdf);List> resultSet = CsvTo2DList.convert(SRC, "|");resultSet.remove(0);for (List record : resultSet) {Div div = new Div().setBorderLeft(new SolidBorder(2)).setPaddingLeft(3).setMarginBottom(10);String url = String.format("/title/tt%s", record.get(0));Link movie = new Link(record.get(2), PdfAction.createURI(url));div.add(new Paragraph(movie.setFontSize(14))).add(new Paragraph(String.format("Directed by %s (%s, %s)",record.get(3), record.get(4), record.get(1))));File file = new File(String.format("src/main/resources/img/%s.jpg", record.get(0)));if (file.exists()) {Image img = new Image(ImageDataFactory.create(file.getPath()));img.scaleToFit(10000, 120);div.add(img);}document.add(div);}document.close();}

和往常一样,我们创建一个PdfDocument和一个Document实例(第2-3行)。其中CSV文件我们重用了前一章节介绍的CSV文件,并遍历这个文件,列出所有电影,不包括标题行(行4-6)。我们创建另一个新的Div对象(行7),将它的左边框定义为2个用户单位的实心边框(行8),并将做填充设置为3个用户单位(行9),下边距设置为10个用户单位(行10)。紧接着我们电影标题Paragraph(行14)和其他信息(行15-17)添加到这个Div中。如果我们可以找到到电影海报,我们会添加Image对象(行24)。最后添加每一个DivDocument中并且关闭这个Document

我们把目光放在第一页的底部和第二页的顶部,也就是电影标题是Dr. Jekyll and Mr. Hyde,导演是John S. RobersonDiv分布到两页上。电影海报在第一页上放不下,所以被放到了第二页。当然这可能不是我们所希望,也许我们希望添加到同一个Div的元素保持在一起,如图4.2所示:

图4.2 让一个div保持在一个页面

我们只需要用一个额外的方法来做到如此,代码如下:

Div div = new Div().setKeepTogether(true).setBorderLeft(new SolidBorder(2)).setPaddingLeft(3).setMarginBottom(10);

通过添加setKeepTogether(true),告诉iText尝试将Div的内容保持在同一页面上。如果该Div的内容适合在下一页,则该Div中所有的元素将被转发到下一页。在图4.2中就是这种情况,上述我们提到Dr. Jekyll and Mr. Hyde电影的标题和信息被转发到下一页。

如果Div的内容不适合下一页,那么此方法将会不起作用。在这种情况下,元素分部在当前页面和后续页面上,就好像未使用setKeepTogether()方法一样。 如果真的想将一个元素与下一个元素保持在同一页面上,有一种解决方法。 在我们讨论了LineSeparator对象之后,我们将看一个演示此解决方法的示例。

2. 使用 LineSeparator对象绘制水平线

相信大家也看到了哈,iText里面的构建块与HTML里面的标签很类似。Text大致对应(空标签),Paragraph对应<p>标签,Div对应<div>标签,以此类推。同理LineSeparator最好的对应标签为<hr>图 4.3显示了一条由红线组成的水平线,1 个用户单位粗,占可用宽度的 50%,为此定义了 5 个用户单位的上边距。

图4.3 添加分割线

代码如下:

SolidLine line = new SolidLine(1f);line.setColor(Color.RED);LineSeparator ls = new LineSeparator(line);ls.setWidthPercent(50);ls.setMarginTop(5);

首先我们传递了厚度参数来创建了一个SolidLine对象。在这里我们回顾一下,在上一章中,SolidLineILineDrawer接口的实现之一。 然后将其颜色设置为红色,并使用此ILineDrawer创建LineSeparator实例。 接着使用setWidthPercent()方法定义线条的宽度。 当然我们也可以使用setWidth()方法来定义以用户单位表示的绝对宽度。 最后,我们将上边距设置为 5 个用户单位。

我们将ls对象添加到包含电影信息的Div元素中。

div.add(ls);

关于LineSeparator基本上就是这些内容。我们只需要记住我们应该使用正确的方法来设置属性。例如:在LineSeparator层面不能改变线的颜色,需要在ILineDrawer层面设置。显得宽度也是如此。我们可以查验附录B来看LineSeparator类实现了哪些AbstractElement方法,以及忽略了哪些方法。

3. 让内容保持在一起

在前面的示例中,我们已经多次使用Paragraph类。 例如:在第 2 章中,我们使用Paragraph类将文本文件转换为 PDF,方法是为文本文件中的每一行创建一个Paragraph对象,并将所有这些Paragraph对象添加到Document实例中 . 前几章的屏幕截图表明,我们可以制作一些非常好的 PDF 文档,但总有改进的余地。

图4.4中展示了我们需要修复的一个缺陷:在第3也上面有个标题,但是那这章的内容却在第4也上面。

图4.4 一个孤独的标题

这种问题我们应该尽量避免,让标题和内容在同一页面上,首先让我们做第一次尝试,采用的代码如下:

public void createPdf(String dest) throws IOException {PdfDocument pdf = new PdfDocument(new PdfWriter(dest));Document document = new Document(pdf);PdfFont font = PdfFontFactory.createFont(FontConstants.TIMES_ROMAN);PdfFont bold = PdfFontFactory.createFont(FontConstants.HELVETICA_BOLD);document.setTextAlignment(TextAlignment.JUSTIFIED).setHyphenation(new HyphenationConfig("en", "uk", 3, 3));BufferedReader br = new BufferedReader(new FileReader(SRC));String line;Div div = new Div();while ((line = br.readLine()) != null) {Paragraph title = new Paragraph(line).setFont(bold).setFontSize(12).setMarginBottom(0);div = new Div().add(title).setFont(font).setFontSize(11).setMarginBottom(18);while ((line = br.readLine()) != null) {div.add(new Paragraph(line).setMarginBottom(0).setFirstLineIndent(36));if (line.isEmpty()) {document.add(div);break;}}}document.add(div);document.close();}

上面代码和我们第2章写的很相似,最主要的区别就是我们不再直接把Paragrah添加到Document中。相反,我们把Paragrah添加到Div中,然后在每个章节的末尾把Div添加到Paragrah中。但是最终我们发现并能做到我们想要的结果。

我们可以在第 15 行和第 16 行之间尝试添加.setKeepTogether(true),但这不会产生任何影响,因为Div里面全部内容在单个页面里面放不下。 这个也提到过了,setKeepTogether()方法会被忽略。 iText 上就如何解决这个问题进行了长时间的研究, 最终定避免寡居对象的最优雅方法是引入setKeepWithNext()方法。

setKeepWithNext()方法是在 iText 7.0.1 中引入的。 第一个 iText 7 版本中找不到这个方法。 iText正在研究是否可以支持嵌套对象的方法, 但是不愿意这样做,因为这可能会对库的整体性能产生重大的负面影响。

如下代码展示了如何使用:

BufferedReader br = new BufferedReader(new FileReader(SRC));String line;Div div = new Div();while ((line = br.readLine()) != null) {document.add(new Paragraph(line).setFont(bold).setFontSize(12).setMarginBottom(0).setKeepWithNext(true));div = new Div().setFont(font).setFontSize(11).setMarginBottom(18);while ((line = br.readLine()) != null) {div.add(new Paragraph(line).setMarginBottom(0).setFirstLineIndent(36));if (line.isEmpty()) {document.add(div);break;}}}document.add(div);

首先把一个Paragraph直接添加到Document(行5);然后创建一个Div来容纳章节剩余内容(行9)。通过添加setKeepWithNext(true)来表明Paragraph需要与Div的(第一部分)保持在同一页面上。 结果如图 4.5所示。 与图 4.4相比,标题“SEARCH FOR MR. HYDE”现在被转发到下一页。

图4.5 让标题和文本保持在一起

setKeepWithNext()方法可以与除Cell之外的所有其他AbstractElement的实现类一起使用。 该方法仅适用于直接添加到Document实例的元素。 它不适用于嵌套对象,例如始终添加到表格而不直接添加到文档的Cell。 在上面示例中,如果标题Paragraph被添加到Div而不是Document,它将不起作用。

4. 更改段落行距

Paragraph类除了实现AbstractElement级别定义的方法之上还有一些额外的方法。 我们已经使用了上一章中涉及TabStops的方法(制表符/制表位)。 上面的例子里面还引用了setFirstLineIndent()方法(改变缩进)。 现在我们将目光放在如何研究行距。

行距-英文leading这个词发音为ledding,它来自铅(金属)这个词。 当为印刷机手动设置字体时,铅条被放置在字体行之间以增加空间。 这个词最初指的是放置在线条之间的这些铅条的厚度。 PDF 标准将前导重新定义为“相邻文本行的基线之间的垂直距离”(ISO-32000-1,第 9.3.5 节)。

有两种方法可以改变段落的行距:

setFixedLeading()—— 将行距更改为绝对值。 例如:如果定义 18 的固定行距,则两行文本的基线之间的距离将为 18 个用户单位。setMultipliedLeading——将行距更改为相对于字体大小的值。 例如,如果定义乘以 1.5f 的行距并且字体为 12 pt,那么前导将为 18 个用户单位(即 1.5 乘以 12)。

这两个方法是相互排斥的。 如果在同一个段落中同时使用这两种方法,则以最后调用的方法为准。图 4.6展示了读取这个故事的另一种转换: 总页数较低,因为我们通过添加 .setMultipliedLeading(1.2f)更改了行之间的距离。

图4.6 改变缩进和行距

实现上述的代码除了以下代码片段以外,和之前的例子几乎一样:

div.add(new Paragraph(line).setMarginBottom(0).setFirstLineIndent(36).setMultipliedLeading(1.2f));

当我们直接或间接(例如通过Div)将对象添加到Document时,iText 使用适当的IRenderer将此对象呈现为 PDF。 在本系列第0章的图 4 里面展示了不同渲染器的概览。一般情况下我们使用 iText 几乎不需要创建自定义渲染器,但我们将看一个示例,在这个示例中我们创建了一个继承(extends)默认ParagraphRendererMyParagraphRenderer

5. 创建自定义渲染器

看如图4.7所示,有两个不同背景的Paragraphs。对于第一个Paragraph,我们使用了.setBackgroundColor()方法,这个方法基于段落的位置画了一个矩形,对于第二个Paragraph,我想要画一个圆角矩形。但是iText 7里面没有方法来做到,做到这我们需要写一个自定义ParagraphRenderer类。

图4.7 段落的默认和自定义背景

让我们看看实现上述效果的代码片段,首先是第一个Paragraph,代码如此:

Paragraph p1 = new Paragraph("The Strange Case of Dr. Jekyll and Mr. Hyde");p1.setBackgroundColor(Color.ORANGE);document.add(p1);

然后是第二个Paragraph,代码如此:

Paragraph p2 = new Paragraph("The Strange Case of Dr. Jekyll and Mr. Hyde");p2.setBackgroundColor(Color.ORANGE);p2.setNextRenderer(new MyParagraphRenderer(p2));document.add(p2);

其中用到的MyParagraphRenderer的定义如下:

class MyParagraphRenderer extends ParagraphRenderer {public MyParagraphRenderer(Paragraph modelElement) {super(modelElement);}@Overridepublic void drawBackground(DrawContext drawContext) {Background background =this.<Background>getProperty(Property.BACKGROUND);if (background != null) {Rectangle bBox = getOccupiedAreaBBox();boolean isTagged =drawContext.isTaggingEnabled()&& getModelElement() instanceof IAccessibleElement;if (isTagged) {drawContext.getCanvas().openTag(new CanvasArtifact());}Rectangle bgArea = applyMargins(bBox, false);if (bgArea.getWidth() <= 0 || bgArea.getHeight() <= 0) {return;}drawContext.getCanvas().saveState().setFillColor(background.getColor()).roundRectangle((double)bgArea.getX() - background.getExtraLeft(),(double)bgArea.getY() - background.getExtraBottom(),(double)bgArea.getWidth()+ background.getExtraLeft() + background.getExtraRight(),(double)bgArea.getHeight()+ background.getExtraTop() + background.getExtraBottom(),5).fill().restoreState();if (isTagged) {drawContext.getCanvas().closeTag();}}}}

我们继承了现有的类ParagraphRenderer并且值覆写了一个方法。从AbstractRenderer类中copy了原始的drawBackground()方法,并且使用了roundRectangle()(行23)代替了rectangle()方法。行24-29里面我们注意到矩形的尺寸可以通过左侧、右侧、顶部和底部的额外空间进行微调。这些额外空间可以通过不同参数的setBackgroundColor()方法来设置(具体为带有4个额外浮点数的变量:extraLeft, extraTop, extraRight, 和extraBottom)。

最后让我们看看ListListItem的例子并结束本篇章。

5. 列表和列表符号

图4.8显示了默认可用的不同类型的列表。其中有编号列表(罗马数字和阿拉伯数字)、带有字母的列表(小写、大写、拉丁、希腊)等等。

图4.8 不同类型的列表

下面代码是前面三种列表如何添加:

List list = new List();list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);list = new List(ListNumberingType.DECIMAL);list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);list = new List(ListNumberingType.ENGLISH_LOWER);list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

行1我们首先声明了没有类型的List。默认情况下,这将生成一个以连字符作(-)为列表符号的列表。 然后在第 2-3 行快速添加了2个列表项; 然后我们将List添加到Document(第 4 行)。之后就是多次重复这四行,例如定义一个十进制数字列表(第 5 行),定义一个带有小写字母的字母列表(第 9 行)。

创建不同类型的列表的参数是一个枚举类:ListNumberingType,这个类有以下几种值:

DECIMAL——列表符号是阿拉伯数字:1、2、3、4、5、…ROMAN_LOWER——列表符号是小写罗马数字:i、ii、iii、iv、v、…ROMAN_UPPER——列表符号为大写罗马数字:I、II、III、IV、V、…ENGLISH_LOWER—— 列表符号是小写字母(使用英文字母):a、b、c、d、e、…ENGLISH_UPPER——列表符号是大写字母(使用英文字母):A、B、C、D、E、…GREEK_LOWER——列表符号为小写希腊字母:α, β, γ, δ, ε,…GREEK_UPPER——列表符号为大写希腊字母:Α、Β、Γ、Δ、Ε、…ZAPF_DINGBATS_1——列表符号是来自 Zapfdingbats 字体的项目符号,更具体地说是 [172; 181]范围内的字符。ZAPF_DINGBATS_2——列表符号是 Zapfdingbats 字体的项目符号,更具体地说是 [182;191]范围内的字符。ZAPF_DINGBATS_3——列表符号是来自 Zapfdingbats 字体的项目符号,更具体地说是 [192; 201]范围内的字符。ZAPF_DINGBATS_4——列表符号是来自 Zapfdingbats 字体的项目符号,更具体地说是 [202; 221]范围内的字符。

显然,我们也可以定义自己的自定义列表符号,或者我们可以使用默认列表符号(例如数字)的组合并将它们与前缀或后缀组合。 效果如图 4.9所示。

图4.9 自定义列表符号

首先我们看一下如何引入一个简单的项目符号作为列表符号,而不是默认的连字符。代码片段如下:

List list = new List();list.setListSymbol("\u");list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

我们创建一个List并使用setListSymbol()方法来更改列表符号,其中可以使用任何String作为列表符号。在我们的例子中,我们想要一个像子弹一样的原点,对应的Unicode值为/u。 但是注意到子弹符号与列表项的内容非常接近。 做到这样可以通过使用setSymbolIndent()方法定义缩进来改变这一点,就像下面例子里面一样:

list = new List();PdfFont font = PdfFontFactory.createFont(FontConstants.ZAPFDINGBATS);list.setListSymbol(new Text("*").setFont(font).setFontColor(Color.ORANGE));list.setSymbolIndent(10);list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

在这里我们将列表符号设置为*,但使用的是Text对象而不是String。 然后将字体设置为 ZapfDingbats。最后还将字体颜色更改为橙色。 最终展示的效果会产生一个看起来像橙色手指的列表符号。 在下一个片段中,我们使用Image对象作为列表符号:

Image info = new Image(ImageDataFactory.create(INFO));info.scaleAbsolute(12, 12);list = new List().setSymbolIndent(3);list.setListSymbol(info);list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

第1行创建了一个Image对象,其中INFO指向了蓝色信息提示的图片。然后缩放图像,使其尺寸为 12 x 12 个用户单位,并将图像作为setListSymbol()方法的参数传递。

在默认列表类型中,iText 总是在编号列表的列表符号后添加一个点:a.、b.、c. 等。 有的时候我们不想要这个点或者用其他符号替换“.”,例如:a-、b-、c- 等等。 下面的代码片段展示了如何实现这一点:

list = new List();list.setListSymbol(ListNumberingType.ENGLISH_LOWER);list.setPostSymbolText("- ");list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

第 1 行和第 2 行相当于list = new List(ListNumberingType.ENGLISH_LOWER); 它会生成一个使用英文字母的编号列表。 然后我们使用setPostSymbolText(方法将每个字母后自动添加的点替换为“-”。

还有一个setPreSymbolText()方法可以在默认列表符号前面添加文本。 以下代码片段创建了一个十进制列表(1.、2.、3.、…),但通过添加前符号和后符号,列表符号已成为如下所示的列表标签:Part 1: ,Part 2:,Part 3 :,等等。

list = new List(ListNumberingType.DECIMAL);list.setPreSymbolText("Part ");list.setPostSymbolText(": ");list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

并非每个编号列表都需要以 1、i、a 等开头。 你还可以使用setItemStartIndex()方法选择以更大的数字(或字母)开头。 在以下代码示例中,我们从 5 开始计数。

list = new List(ListNumberingType.DECIMAL);list.setItemStartIndex(5);list.add("Dr. Jekyll");list.add("Mr. Hyde");document.add(list);

最后,我们将使用setListSymbolAlignment()来更改标签的对齐方式。 例如图 4.8中的小写罗马数字列表与图 4.9 中的列表进行比较,你会发现列表标签的对齐方式有所不同。

list = new List(ListNumberingType.ROMAN_LOWER);list.setListSymbolAlignment(ListSymbolAlignment.LEFT);for (int i = 0; i < 6; i++) {list.add("Dr. Jekyll");list.add("Mr. Hyde");}document.add(list);

到目前为止,我们一直使用字符串将列表项添加到列表中, 其实这些String值在内部更改为ListItems

7. 将 ListItem 对象添加到List

在第0章的类图里面,我们可以看到ListItem类是Div类的子类。和Div一样类似,我们可以在列表上下文里面添加不同对象。

以本章第一个例子为引,我们不用Div而使用ListItems,展现的效果如图10所示

图4.10 List items

代码和Div的例子很像:

public void createPdf(String dest) throws IOException {PdfDocument pdf = new PdfDocument(new PdfWriter(dest));Document document = new Document(pdf);List<List<String>> resultSet = CsvTo2DList.convert(SRC, "|");resultSet.remove(0);com.itextpdf.layout.element.List list =new com.itextpdf.layout.element.List(ListNumberingType.DECIMAL);for (List record : resultSet) {ListItem li = new ListItem();li.setKeepTogether(true);String url = String.format("/title/tt%s", record.get(0));Link movie = new Link(record.get(2), PdfAction.createURI(url));li.add(new Paragraph(movie.setFontSize(14))).add(new Paragraph(String.format("Directed by %s (%s, %s)",record.get(3), record.get(4), record.get(1))));File file = new File(String.format("src/main/resources/img/%s.jpg", record.get(0)));if (file.exists()) {Image img = new Image(ImageDataFactory.create(file.getPath()));img.scaleToFit(10000, 120);li.add(img);}list.add(li);}document.add(list);document.close();}

先解析数据到java.util.List(行4),然后声明了全路径com.itextpdf.layout.element.List来避免编译器混淆(行6),并创建了数字列表(行7)。接着为java.util.List中的每个项目创建一个ListItem(行9)。然后添加Paragraphs和Image(如果有的话)添加到这个ListItem中(行11-24)。最后我们把每个ListItem添加到List中(行25),最终把这个List添加到Document中。

8. 嵌套列表

本章最后一个例子是创建嵌套列表,展示的效果如图4.11所示:

图4.11 嵌套列表

这个例子里面变量很难多,看起来比较绕,又复杂,所以我们简单拆成几部分来讲。首先我们从一个常规列表开始,变量名称为list。

List list = new List();

我们创建一个数字列表list1(行1)。这个列表有两个ListItems,liEL(行5)和liEU(行11)。同时对应这两个ListItem创建对应的List:listEL(行2,小写英文字母)和listEU(行8,大写英文字母),并为每个List添加列表元素“Dr. Jekyll”和“Mr. Hyde”。(行3-4,行9-10)。

List list1 = new List(ListNumberingType.DECIMAL);List listEL = new List(ListNumberingType.ENGLISH_LOWER);listEL.add("Dr. Jekyll");listEL.add("Mr. Hyde");ListItem liEL = new ListItem();liEL.add(listEL);list1.add(liEL);List listEU = new List(ListNumberingType.ENGLISH_UPPER);listEU.add("Dr. Jekyll");listEU.add("Mr. Hyde");ListItem liEU = new ListItem();liUL.add(listEU);list1.add(liEU);ListItem li1 = new ListItem();li1.add(list1);list.add(li1);

对应图4.11所示,首先是分割符,然后可以看见数字列表符号1. 和 2. ,同时内部嵌套了两个使用小写英文字母的列表元素的列表。

在下一个代码片段,我们创建了另一个属于list的ListItem,对应变量名称为li(行1)。然后我们往这个ListItem添加4个列表:listGL(行2),listGU(行6),listRL(行10)和listRU(行14)。这些列表(希腊字母小写,希腊字母大写,罗马数字小写,罗马数字大写)依次添加到默认到具有默认列表符号的列表项。

ListItem li = new ListItem();List listGL = new List(ListNumberingType.GREEK_LOWER);listGL.add("Dr. Jekyll");listGL.add("Mr. Hyde");li.add(listGL);List listGU = new List(ListNumberingType.GREEK_UPPER);listGU.add("Dr. Jekyll");listGU.add("Mr. Hyde");li.add(listGU);List listRL = new List(ListNumberingType.ROMAN_LOWER);listRL.add("Dr. Jekyll");listRL.add("Mr. Hyde");li.add(listRL);List listRU = new List(ListNumberingType.ROMAN_UPPER);listRU.add("Dr. Jekyll");listRU.add("Mr. Hyde");li.add(listRU);list.add(li);

此外,我们创建了一个带有编号的ZapfDingbats项目符号列表(listZ1),并把这个列表添加到列表元素(变量名为liZ1):

List listZ1 = new List(ListNumberingType.ZAPF_DINGBATS_1);listZ1.add("Dr. Jekyll");listZ1.add("Mr. Hyde");ListItem liZ1 = new ListItem();liZ1.add(listZ1);

接着创建第二个带有不同ZapfDingbats项目符号的列表(listZ2),并把这个列表添加到列表元素(变量名为liZ2):

List listZ2 = new List(ListNumberingType.ZAPF_DINGBATS_2);listZ2.add("Dr. Jekyll");listZ2.add("Mr. Hyde");ListItem liZ2 = new ListItem();liZ2.add(listZ2);

接着创建第三个带有不同ZapfDingbats项目符号的列表(listZ3),并把这个列表添加到列表元素(变量名为liZ3):

List listZ3 = new List(ListNumberingType.ZAPF_DINGBATS_3);listZ3.add("Dr. Jekyll");listZ3.add("Mr. Hyde");ListItem liZ3 = new ListItem();liZ3.add(listZ3);

最后创建第四个带有不同ZapfDingbats项目符号的列表(listZ4),并把这个列表添加到列表元素(变量名为liZ4):

List listZ4 = new List(ListNumberingType.ZAPF_DINGBATS_4);listZ4.add("Dr. Jekyll");listZ4.add("Mr. Hyde");ListItem liZ4 = new ListItem();liZ4.add(listZ4);

接着我们做如下的事情来完成嵌套:

把liZ4添加到listZ3,其中listZ3已经被添加到liZ3;把liZ3添加到listZ2,其中listZ2已经被添加到liZ2;把liZ2添加到listZ1,其中listZ1已经被添加到liZ1;把liZ1添加到list,也就是一开始我们创建的默认分隔符的列表;

最后我们把list添加到Document

listZ3.add(liZ4);listZ2.add(liZ3);listZ1.add(liZ2);list.add(liZ1);document.add(list);

最终的效果如上图所属,列表的某个元素可以为列表。

9. 总结

在本章中,我们讨论了构建块DivLineSeparatorParagraphListListItem。 我们使用Div对其他构建块进行分组,使用LineSeparator绘制水平线。 我们解决了第 2 章示例中可能遇到的问题:如何将特定元素放在通一个页面上。 同时我们没有详细介绍IRenderer实现,但是罗列一个示例——更改了段落绘制背景的方式。 为此创建了一个自定义的ParagraphRenderer来实现这一点。 最后,我们创建了一些List示例来演示不同类型的列表(编号、未编号、直截了当方式添加、嵌套添加等)。

下一章我们把目光聚集在表格,具体就是TableCell类。

iText7高级教程之构建基础块源码下载-CSDN

本章代码资源下载地址:

关注我的微信公众号CuteXiaoKe,点击代码资源-iText官网代码即可或者直接点击微信文章

如果觉得《iText7高级教程之构建基础块——4.使用AbstractElement对象(part 1)》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。