The pw.MultiPage widget automatically flows content across multiple pages, creating page breaks when content exceeds the available space.
Key Concepts
- Automatic Page Breaks: New pages are created when children don't fit.
- Headers and Footers: These are defined per page. Their space is reserved before the main content is laid out.
- Spanning vs. Inseparable Widgets:
- Spanning Widgets:
pw.Flex, pw.Partition, pw.Table, pw.Wrap, pw.GridView, and pw.Column can split across page boundaries. - Inseparable Widgets: Use
pw.Inseparable to wrap content that must stay together on a single page. If the content doesn't fit, it will trigger a page break.
- Manual Page Breaks: Use
pw.NewPage() to force a break. You can provide freeSpace (e.g., pw.NewPage(freeSpace: 40)) to only break if less than that amount of space remains. - Safety: A
maxPages limit (default 20) is enforced in debug mode to prevent infinite loops during pagination.
pdf.addPage(pw.MultiPage(
pageFormat: PdfPageFormat.a4,
header: (context) => pw.Padding(
padding: const pw.EdgeInsets.only(bottom: 8),
child: pw.Text('Document Header'),
),
footer: (context) => pw.Padding(
padding: const pw.EdgeInsets.only(top: 8),
child: pw.Row(
mainAxisAlignment: pw.MainAxisAlignment.spaceBetween,
children: [
pw.Text('Footer'),
pw.Text('Page ${context.pageNumber} of ${context.pagesCount}'),
],
),
),
build: (context) => [
pw.Text('Section 1: Introduction'),
pw.SizedBox(height: 20),
// Spanning content
pw.Wrap(
spacing: 8,
runSpacing: 8,
children: List.generate(50, (i) => pw.Container(
padding: const pw.EdgeInsets.all(8),
decoration: pw.BoxDecoration(
border: pw.Border.all(),
borderRadius: const pw.BorderRadius.all(pw.Radius.circular(4)),
),
child: pw.Text('Item $i'),
)),
),
pw.NewPage(), // Force page break
// Inseparable content
pw.Inseparable(
child: pw.Column(
crossAxisAlignment: pw.CrossAxisAlignment.start,
children: [
pw.Text('• This content must stay together'),
pw.Text('• It cannot be split across pages'),
],
),
),
],
));