iText7 по-прежнему позволяет вам получить аналог текущей вертикальной позиции, но, как отметил @mkl в своем комментарии, в этой концепции есть много нюансов, поскольку iText7 поддерживает гораздо более сложные стратегии компоновки.
Как правило, при переходе с iText5 на iText7 вы должны стараться мыслить «нестандартно» - есть множество вещей, которые вы можете сделать намного проще с iText7, включая ваш пример использования добавления контента внизу последней страницы.
Вы можете использовать аналог iText7 абсолютного позиционирования CSS, чтобы добавить контент внизу. Для этого необходимо указать свойство position
, а также смещение bottom
. По-прежнему нет причудливого публичного API для этого, потому что функциональность все еще находится в постоянном улучшении, но вы можете сделать это, установив необходимые свойства вручную. Все, что вам нужно сделать, это добавить эти строки:
glueToBottom.setProperty(Property.POSITION, LayoutPosition.ABSOLUTE);
glueToBottom.setProperty(Property.BOTTOM, 0);
Чтобы продемонстрировать результат, давайте сначала добавим некоторый контент, а затем элемент блока в конец последней страницы.
Document document = new Document(pdfDocument);
for (int i = 0; i < 40; i++) {
document.add(new Paragraph("Hello " + i));
}
IBlockElement glueToBottom = new Paragraph("Hi, I am the bottom content")
.setFontSize(25)
.setWidth(UnitValue.createPercentValue(100))
.setBackgroundColor(ColorConstants.RED)
.setTextAlignment(TextAlignment.CENTER);
glueToBottom.setProperty(Property.POSITION, LayoutPosition.ABSOLUTE);
glueToBottom.setProperty(Property.BOTTOM, 0);
document.add(glueToBottom);
document.close();
Вы получите что-то вроде этого на странице 2 (последняя страница), которая точно соответствует вашему описанию:
UPD: Данный алгоритм был обновлен и теперь содержит логику вставки новой страницы для содержимого внизу страницы, если содержимое внизу будет перекрываться с существующим содержимым, если страница не была был вставлен. Чтобы добиться того же поведения, вам понадобится небольшая модификация приведенного выше кода: вместо установки свойств позиционирования с помощью setProperty
давайте реализуем наш собственный элемент и соответствующий модуль рендеринга и поместим ваш блочный элемент в эту реализацию. Теперь мы добавим наш элемент следующим образом:
document.add(new BottomBlockElement(glueToBottom));
Реализации просты - просто переместите элемент вниз, между его разметкой и рисованием. Это немного многословно в коде, но все еще довольно ясно:
private static class BottomBlockElement extends Div {
public BottomBlockElement(IBlockElement wrapping) {
super();
add(wrapping);
setKeepTogether(true);
}
@Override
protected IRenderer makeNewRenderer() {
return new BottomBlockRenderer(this);
}
}
private static class BottomBlockRenderer extends DivRenderer {
public BottomBlockRenderer(BottomBlockElement modelElement) {
super(modelElement);
}
@Override
public LayoutResult layout(LayoutContext layoutContext) {
LayoutResult result = super.layout(layoutContext);
if (result.getStatus() == LayoutResult.FULL) {
float leftoverHeight = result.getOccupiedArea().getBBox().getBottom() - layoutContext.getArea().getBBox().getBottom();
move(0, -leftoverHeight);
return new LayoutResult(result.getStatus(), layoutContext.getArea(), result.getSplitRenderer(), result.getOverflowRenderer());
} else {
return result;
}
}
@Override
public IRenderer getNextRenderer() {
return new BottomBlockRenderer((BottomBlockElement) modelElement);
}
}
Теперь наша основная часть выглядит так:
Document document = new Document(pdfDocument);
for (int i = 0; i < 58; i++) {
document.add(new Paragraph("Hello " + i));
}
IBlockElement glueToBottom = new Paragraph("Hi, I am the bottom content")
.setFontSize(25)
.setWidth(UnitValue.createPercentValue(100))
.setBorder(new SolidBorder(ColorConstants.RED, 1))
.setTextAlignment(TextAlignment.CENTER);
document.add(new BottomBlockElement(glueToBottom));
document.close();
И результатом является последняя страница, содержащая только нижний блок, если на предыдущей не хватает места: