Committed by
David PHAM-VAN
Add custom pages builder to PdfPreview widget
Showing
6 changed files
with
143 additions
and
23 deletions
@@ -22,7 +22,12 @@ import 'package:pdf/pdf.dart'; | @@ -22,7 +22,12 @@ import 'package:pdf/pdf.dart'; | ||
22 | import '../callback.dart'; | 22 | import '../callback.dart'; |
23 | import '../printing.dart'; | 23 | import '../printing.dart'; |
24 | import '../printing_info.dart'; | 24 | import '../printing_info.dart'; |
25 | +import 'page.dart'; | ||
25 | import 'raster.dart'; | 26 | import 'raster.dart'; |
27 | +/// Custom widget builder that's used for custom | ||
28 | +/// rasterized pdf pages rendering | ||
29 | +typedef CustomPdfPagesBuilder = Widget Function( | ||
30 | + BuildContext context, List<PdfPreviewPageData> pages); | ||
26 | 31 | ||
27 | /// Flutter widget that uses the rasterized pdf pages to display a document. | 32 | /// Flutter widget that uses the rasterized pdf pages to display a document. |
28 | class PdfPreviewCustom extends StatefulWidget { | 33 | class PdfPreviewCustom extends StatefulWidget { |
@@ -43,6 +48,7 @@ class PdfPreviewCustom extends StatefulWidget { | @@ -43,6 +48,7 @@ class PdfPreviewCustom extends StatefulWidget { | ||
43 | this.dpi, | 48 | this.dpi, |
44 | this.scrollPhysics, | 49 | this.scrollPhysics, |
45 | this.shrinkWrap = false, | 50 | this.shrinkWrap = false, |
51 | + this.pagesBuilder, | ||
46 | }) : super(key: key); | 52 | }) : super(key: key); |
47 | 53 | ||
48 | /// Pdf paper page format | 54 | /// Pdf paper page format |
@@ -91,6 +97,10 @@ class PdfPreviewCustom extends StatefulWidget { | @@ -91,6 +97,10 @@ class PdfPreviewCustom extends StatefulWidget { | ||
91 | /// If not provided, this value is calculated. | 97 | /// If not provided, this value is calculated. |
92 | final double? dpi; | 98 | final double? dpi; |
93 | 99 | ||
100 | + /// clients can pass this builder to render | ||
101 | + /// their own pages. | ||
102 | + final CustomPdfPagesBuilder? pagesBuilder; | ||
103 | + | ||
94 | @override | 104 | @override |
95 | PdfPreviewCustomState createState() => PdfPreviewCustomState(); | 105 | PdfPreviewCustomState createState() => PdfPreviewCustomState(); |
96 | } | 106 | } |
@@ -183,6 +193,9 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | @@ -183,6 +193,9 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | ||
183 | ); | 193 | ); |
184 | } | 194 | } |
185 | 195 | ||
196 | + if (widget.pagesBuilder != null) { | ||
197 | + return widget.pagesBuilder!(context, pages); | ||
198 | + } | ||
186 | return ListView.builder( | 199 | return ListView.builder( |
187 | controller: scrollController, | 200 | controller: scrollController, |
188 | shrinkWrap: widget.shrinkWrap, | 201 | shrinkWrap: widget.shrinkWrap, |
@@ -197,7 +210,11 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | @@ -197,7 +210,11 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | ||
197 | transformationController.value.setIdentity(); | 210 | transformationController.value.setIdentity(); |
198 | }); | 211 | }); |
199 | }, | 212 | }, |
200 | - child: pages[index], | 213 | + child: PdfPreviewPage( |
214 | + pageData: pages[index], | ||
215 | + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, | ||
216 | + pageMargin: widget.previewPageMargin, | ||
217 | + ), | ||
201 | ), | 218 | ), |
202 | ); | 219 | ); |
203 | } | 220 | } |
@@ -212,7 +229,13 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | @@ -212,7 +229,13 @@ class PdfPreviewCustomState extends State<PdfPreviewCustom> | ||
212 | child: InteractiveViewer( | 229 | child: InteractiveViewer( |
213 | transformationController: transformationController, | 230 | transformationController: transformationController, |
214 | maxScale: 5, | 231 | maxScale: 5, |
215 | - child: Center(child: pages[preview!]), | 232 | + child: Center( |
233 | + child: PdfPreviewPage( | ||
234 | + pageData: pages[preview!], | ||
235 | + pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, | ||
236 | + pageMargin: widget.previewPageMargin, | ||
237 | + ), | ||
238 | + ), | ||
216 | ), | 239 | ), |
217 | ); | 240 | ); |
218 | } | 241 | } |
@@ -15,25 +15,61 @@ | @@ -15,25 +15,61 @@ | ||
15 | */ | 15 | */ |
16 | 16 | ||
17 | import 'package:flutter/material.dart'; | 17 | import 'package:flutter/material.dart'; |
18 | +/// A class that holds rasterized pdf data | ||
19 | +class PdfPreviewPageData { | ||
20 | + /// Default constructor | ||
21 | + const PdfPreviewPageData({ | ||
22 | + required this.image, | ||
23 | + required this.width, | ||
24 | + required this.height, | ||
25 | + }); | ||
26 | + | ||
27 | + /// rasterized pdf image provider | ||
28 | + final ImageProvider image; | ||
29 | + /// rasterized image width | ||
30 | + final int width; | ||
31 | + /// rasterized image height | ||
32 | + final int height; | ||
33 | + | ||
34 | + /// returns with to height aspect ratio | ||
35 | + double get aspectRatio { | ||
36 | + if (height != 0.0) { | ||
37 | + return width / height; | ||
38 | + } | ||
39 | + if (width > 0.0) { | ||
40 | + return double.infinity; | ||
41 | + } | ||
42 | + if (width < 0.0) { | ||
43 | + return double.negativeInfinity; | ||
44 | + } | ||
45 | + return 0.0; | ||
46 | + } | ||
47 | + | ||
48 | + @override | ||
49 | + bool operator ==(Object other) => | ||
50 | + identical(this, other) || | ||
51 | + other is PdfPreviewPageData && | ||
52 | + runtimeType == other.runtimeType && | ||
53 | + image == other.image && | ||
54 | + width == other.width && | ||
55 | + height == other.height; | ||
56 | + | ||
57 | + @override | ||
58 | + int get hashCode => image.hashCode ^ width.hashCode ^ height.hashCode; | ||
59 | +} | ||
18 | 60 | ||
19 | /// Represents one PDF page | 61 | /// Represents one PDF page |
20 | class PdfPreviewPage extends StatelessWidget { | 62 | class PdfPreviewPage extends StatelessWidget { |
21 | /// Create a PDF page widget | 63 | /// Create a PDF page widget |
22 | const PdfPreviewPage({ | 64 | const PdfPreviewPage({ |
23 | Key? key, | 65 | Key? key, |
24 | - required this.image, | ||
25 | - required this.width, | ||
26 | - required this.height, | 66 | + required this.pageData, |
27 | this.pdfPreviewPageDecoration, | 67 | this.pdfPreviewPageDecoration, |
28 | this.pageMargin, | 68 | this.pageMargin, |
29 | }) : super(key: key); | 69 | }) : super(key: key); |
30 | 70 | ||
31 | /// Image representing the content of the page | 71 | /// Image representing the content of the page |
32 | - final ImageProvider image; | ||
33 | - | ||
34 | - final int width; | ||
35 | - | ||
36 | - final int height; | 72 | + final PdfPreviewPageData pageData; |
37 | 73 | ||
38 | /// Decoration around the page | 74 | /// Decoration around the page |
39 | final Decoration? pdfPreviewPageDecoration; | 75 | final Decoration? pdfPreviewPageDecoration; |
@@ -69,9 +105,9 @@ class PdfPreviewPage extends StatelessWidget { | @@ -69,9 +105,9 @@ class PdfPreviewPage extends StatelessWidget { | ||
69 | ], | 105 | ], |
70 | ), | 106 | ), |
71 | child: AspectRatio( | 107 | child: AspectRatio( |
72 | - aspectRatio: width / height, | 108 | + aspectRatio: pageData.aspectRatio, |
73 | child: Image( | 109 | child: Image( |
74 | - image: image, | 110 | + image: pageData.image, |
75 | fit: BoxFit.cover, | 111 | fit: BoxFit.cover, |
76 | ), | 112 | ), |
77 | ), | 113 | ), |
@@ -26,6 +26,7 @@ import 'controller.dart'; | @@ -26,6 +26,7 @@ import 'controller.dart'; | ||
26 | import 'custom.dart'; | 26 | import 'custom.dart'; |
27 | 27 | ||
28 | export 'custom.dart'; | 28 | export 'custom.dart'; |
29 | +export 'page.dart' show PdfPreviewPageData; | ||
29 | 30 | ||
30 | /// Flutter widget that uses the rasterized pdf pages to display a document. | 31 | /// Flutter widget that uses the rasterized pdf pages to display a document. |
31 | class PdfPreview extends StatefulWidget { | 32 | class PdfPreview extends StatefulWidget { |
@@ -61,7 +62,66 @@ class PdfPreview extends StatefulWidget { | @@ -61,7 +62,66 @@ class PdfPreview extends StatefulWidget { | ||
61 | this.loadingWidget, | 62 | this.loadingWidget, |
62 | this.onPageFormatChanged, | 63 | this.onPageFormatChanged, |
63 | this.dpi, | 64 | this.dpi, |
64 | - }) : super(key: key); | 65 | + }) : _pagesBuilder = null, |
66 | + super(key: key); | ||
67 | + | ||
68 | + /// Build a custom layout. | ||
69 | + /// | ||
70 | + /// ```dart | ||
71 | + /// PdfPreview.builder( | ||
72 | + /// build: (format) => _generatePdf(format, title), | ||
73 | + /// pagesBuilder: (context, pages) => SingleChildScrollView( | ||
74 | + /// child: Wrap( | ||
75 | + /// spacing: 8, | ||
76 | + /// runSpacing: 8, | ||
77 | + /// children: [ | ||
78 | + /// for (final page in pages) | ||
79 | + /// Container( | ||
80 | + /// color: Colors.white, | ||
81 | + /// child: Image( | ||
82 | + /// image: page.image, | ||
83 | + /// width: 300, | ||
84 | + /// ), | ||
85 | + /// ) | ||
86 | + /// ], | ||
87 | + /// ), | ||
88 | + /// ), | ||
89 | + /// ) | ||
90 | + /// ``` | ||
91 | + const PdfPreview.builder({ | ||
92 | + Key? key, | ||
93 | + required this.build, | ||
94 | + this.initialPageFormat, | ||
95 | + this.allowPrinting = true, | ||
96 | + this.allowSharing = true, | ||
97 | + this.maxPageWidth, | ||
98 | + this.canChangePageFormat = true, | ||
99 | + this.canChangeOrientation = true, | ||
100 | + this.canDebug = true, | ||
101 | + this.actions, | ||
102 | + this.pageFormats = _defaultPageFormats, | ||
103 | + this.onError, | ||
104 | + this.onPrinted, | ||
105 | + this.onPrintError, | ||
106 | + this.onShared, | ||
107 | + this.scrollViewDecoration, | ||
108 | + this.pdfPreviewPageDecoration, | ||
109 | + this.pdfFileName, | ||
110 | + this.useActions = true, | ||
111 | + this.pages, | ||
112 | + this.dynamicLayout = true, | ||
113 | + this.shareActionExtraBody, | ||
114 | + this.shareActionExtraSubject, | ||
115 | + this.shareActionExtraEmails, | ||
116 | + this.previewPageMargin, | ||
117 | + this.padding, | ||
118 | + this.shouldRepaint = false, | ||
119 | + this.loadingWidget, | ||
120 | + this.onPageFormatChanged, | ||
121 | + this.dpi, | ||
122 | + required CustomPdfPagesBuilder pagesBuilder, | ||
123 | + }) : _pagesBuilder = pagesBuilder, | ||
124 | + super(key: key); | ||
65 | 125 | ||
66 | static const _defaultPageFormats = <String, PdfPageFormat>{ | 126 | static const _defaultPageFormats = <String, PdfPageFormat>{ |
67 | 'A4': PdfPageFormat.a4, | 127 | 'A4': PdfPageFormat.a4, |
@@ -163,6 +223,10 @@ class PdfPreview extends StatefulWidget { | @@ -163,6 +223,10 @@ class PdfPreview extends StatefulWidget { | ||
163 | /// If not provided, this value is calculated. | 223 | /// If not provided, this value is calculated. |
164 | final double? dpi; | 224 | final double? dpi; |
165 | 225 | ||
226 | + /// clients can pass this builder to render | ||
227 | + /// their own pages. | ||
228 | + final CustomPdfPagesBuilder? _pagesBuilder; | ||
229 | + | ||
166 | @override | 230 | @override |
167 | _PdfPreviewState createState() => _PdfPreviewState(); | 231 | _PdfPreviewState createState() => _PdfPreviewState(); |
168 | } | 232 | } |
@@ -331,6 +395,7 @@ class _PdfPreviewState extends State<PdfPreview> { | @@ -331,6 +395,7 @@ class _PdfPreviewState extends State<PdfPreview> { | ||
331 | previewPageMargin: widget.previewPageMargin, | 395 | previewPageMargin: widget.previewPageMargin, |
332 | scrollViewDecoration: widget.scrollViewDecoration, | 396 | scrollViewDecoration: widget.scrollViewDecoration, |
333 | shouldRepaint: widget.shouldRepaint, | 397 | shouldRepaint: widget.shouldRepaint, |
398 | + pagesBuilder: widget._pagesBuilder, | ||
334 | dpi: widget.dpi, | 399 | dpi: widget.dpi, |
335 | ); | 400 | ); |
336 | }), | 401 | }), |
@@ -38,7 +38,7 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { | @@ -38,7 +38,7 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { | ||
38 | PdfPageFormat get pageFormat => widget.pageFormat; | 38 | PdfPageFormat get pageFormat => widget.pageFormat; |
39 | 39 | ||
40 | /// Resulting pages | 40 | /// Resulting pages |
41 | - final pages = <PdfPreviewPage>[]; | 41 | + final pages = <PdfPreviewPageData>[]; |
42 | 42 | ||
43 | /// Printing subsystem information | 43 | /// Printing subsystem information |
44 | PrintingInfo? info; | 44 | PrintingInfo? info; |
@@ -167,23 +167,18 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { | @@ -167,23 +167,18 @@ mixin PdfPreviewRaster on State<PdfPreviewCustom> { | ||
167 | _rastering = false; | 167 | _rastering = false; |
168 | return; | 168 | return; |
169 | } | 169 | } |
170 | - | ||
171 | if (pages.length <= pageNum) { | 170 | if (pages.length <= pageNum) { |
172 | - pages.add(PdfPreviewPage( | 171 | + pages.add(PdfPreviewPageData( |
173 | image: MemoryImage(await page.toPng()), | 172 | image: MemoryImage(await page.toPng()), |
174 | width: page.width, | 173 | width: page.width, |
175 | height: page.height, | 174 | height: page.height, |
176 | - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, | ||
177 | - pageMargin: widget.previewPageMargin, | ||
178 | )); | 175 | )); |
179 | } else { | 176 | } else { |
180 | pages[pageNum].image.evict(); | 177 | pages[pageNum].image.evict(); |
181 | - pages[pageNum] = PdfPreviewPage( | 178 | + pages[pageNum] = PdfPreviewPageData( |
182 | image: MemoryImage(await page.toPng()), | 179 | image: MemoryImage(await page.toPng()), |
183 | width: page.width, | 180 | width: page.width, |
184 | height: page.height, | 181 | height: page.height, |
185 | - pdfPreviewPageDecoration: widget.pdfPreviewPageDecoration, | ||
186 | - pageMargin: widget.previewPageMargin, | ||
187 | ); | 182 | ); |
188 | } | 183 | } |
189 | 184 |
@@ -6,7 +6,7 @@ description: > | @@ -6,7 +6,7 @@ description: > | ||
6 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing | 6 | homepage: https://github.com/DavBfr/dart_pdf/tree/master/printing |
7 | repository: https://github.com/DavBfr/dart_pdf | 7 | repository: https://github.com/DavBfr/dart_pdf |
8 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues | 8 | issue_tracker: https://github.com/DavBfr/dart_pdf/issues |
9 | -version: 5.9.4 | 9 | +version: 5.10.0 |
10 | 10 | ||
11 | environment: | 11 | environment: |
12 | sdk: ">=2.12.0 <3.0.0" | 12 | sdk: ">=2.12.0 <3.0.0" |
-
Please register or login to post a comment