Flutter开发APP:如何生成与指定样式匹配的自定义PDF?
Flutter生成自定义PDF的实现思路与方法
一、核心依赖选择
在Flutter中生成自定义PDF,优先选用以下两个维护成熟的包:
pdf:负责PDF文档的构建与布局渲染,支持用Flutter Widget语法编写PDF内容,降低学习成本printing:提供PDF预览、保存、分享、打印等配套功能,和pdf包完美兼容
在pubspec.yaml中添加依赖:
dependencies: pdf: ^3.10.0 printing: ^5.12.0
二、布局还原思路(匹配目标样式)
从你提供的PDF样式来看,包含标题、表格、多行文本、签名栏等元素,还原步骤如下:
- 页面基础配置
设置PDF页面尺寸(默认A4)、边距,确保整体布局和目标样式对齐:
final doc = pw.Document(); doc.addPage( pw.Page( margin: const pw.EdgeInsets.all(16), build: (pw.Context context) { // 页面内容在此构建 }, ), );
- 文本与标题处理
用pw.Text组件设置不同字号、粗细,还原标题和正文的层级样式:
pw.Text("申请单", style: pw.TextStyle(fontSize: 20, fontWeight: pw.FontWeight.bold)), pw.SizedBox(height: 10), pw.Text("申请人:${formData['name']}", style: pw.TextStyle(fontSize: 14)),
- 表格布局实现
目标样式中的表格部分,用pw.Table组件实现,配置边框、单元格对齐和内边距:
pw.Table( border: pw.TableBorder.all(width: 1), children: [ pw.TableRow( children: [ pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text("项目")), pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text("内容")), ], ), pw.TableRow( children: [ pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text("申请事由")), pw.Padding(padding: const pw.EdgeInsets.all(8), child: pw.Text(formData['reason'])), ], ), // 补充更多表格行 ], ),
- 自定义区块(如签名栏)
签名栏用pw.Row组合文本和横线实现,控制对齐方式:
pw.Row( mainAxisAlignment: pw.MainAxisAlignment.end, children: [ pw.Column( children: [ pw.Text("申请人签名"), pw.SizedBox(height: 5), pw.Container(width: 120, height: 1, color: pw.Colors.black), pw.Text(formData['signName']), ], ), ], ),
- 中文字体适配
默认字体不支持中文,需加载自定义字体(如思源黑体):
final font = await rootBundle.load("fonts/SourceHanSansCN-Normal.ttf"); final ttf = pw.Font.ttf(font); // 在Text组件中指定字体 pw.Text("中文内容", style: pw.TextStyle(font: ttf)),
三、数据填充与生成流程
- 收集表单数据
从应用内表单的TextEditingController、下拉选择框等组件中,将用户填写的数据整理为Map或实体类:
final formData = { 'name': nameController.text, 'reason': reasonController.text, 'signName': signNameController.text, // 其他字段 };
构建PDF文档
将收集到的数据填充到上述布局组件中,完成PDF文档的构建。预览与导出
用printing包实现PDF的预览、保存或分享:
- 预览:
PdfPreview( build: (context) => generatePdf(formData), ); - 保存到本地:
await Printing.layoutPdf( onLayout: (format) async => generatePdf(formData).save(), ); - 分享PDF:
await Printing.sharePdf( bytes: await generatePdf(formData).save(), filename: "申请单.pdf", );
四、细节优化建议
- 测试不同设备的渲染效果,确保PDF样式跨平台一致
- 长文本使用
pw.Wrap或pw.Expanded组件避免内容溢出 - 需要添加图片(如logo)时,用
pw.Image加载本地资源或网络图片
内容的提问来源于stack exchange,提问作者GitGud31
相关产品推荐
相关产品推荐

