如何将Flutter页面转为支持文本选中的PDF(非图片形式)
实现Flutter页面转可选中文本PDF的方案
要生成包含可选中文本的PDF,核心是直接构建PDF原生文本元素,而非将页面截图插入PDF。以下是两种实用方案:
方案一:使用pdf + printing包直接构建PDF内容
这是最可靠的方式,通过pdf包提供的原生PDF组件构建内容,所有文本均为可选中状态。
- 添加依赖到
pubspec.yaml
dependencies: pdf: ^3.10.0 printing: ^5.12.0
- 编写PDF生成代码
将原Flutter页面的布局逻辑,用pdf包的组件重新实现(常用布局组件如文本、列、行、表格等都有对应实现):
import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; import 'package:path_provider/path_provider.dart'; import 'dart:io'; import 'package:flutter/services.dart'; Future<void> generateSelectablePdf() async { final pdf = pw.Document(); // 加载自定义字体(可选,若使用系统字体可跳过) final customFont = await pw.Font.ttf(await rootBundle.load('assets/fonts/NotoSansSC-Regular.ttf')); // 构建PDF页面内容 pdf.addPage( pw.Page( pageFormat: PdfPageFormat.a4, build: (pw.Context context) { return pw.Container( padding: pw.EdgeInsets.all(20), child: pw.Column( crossAxisAlignment: pw.CrossAxisAlignment.start, children: [ pw.Text( 'Flutter生成的可选中PDF', style: pw.TextStyle( font: customFont, fontSize: 24, fontWeight: pw.FontWeight.bold, ), ), pw.SizedBox(height: 16), pw.Text( '这段文本可以直接选中复制,因为它是PDF原生文本元素,而非图片。', style: pw.TextStyle(font: customFont, fontSize: 16), ), pw.SizedBox(height: 16), pw.Column( children: [ pw.Text('• 列表项1', style: pw.TextStyle(font: customFont, fontSize: 16)), pw.Text('• 列表项2', style: pw.TextStyle(font: customFont, fontSize: 16)), ], ), ], ), ); }, ), ); // 保存PDF到本地 final tempDir = await getTemporaryDirectory(); final file = File('${tempDir.path}/selectable_pdf.pdf'); await file.writeAsBytes(await pdf.save()); // 也可以直接分享PDF // await Printing.sharePdf(bytes: await pdf.save(), filename: 'selectable_pdf.pdf'); }
方案二:通过HTML转PDF(适合快速适配现有内容)
如果你的页面内容可以快速转换为HTML格式,可利用pdf包的Html组件渲染,同样生成可选中的文本。
同样依赖
pdf和printing包(同方案一)编写HTML转PDF代码
import 'package:pdf/pdf.dart'; import 'package:pdf/widgets.dart' as pw; import 'package:printing/printing.dart'; Future<void> generatePdfFromHtml() async { final pdf = pw.Document(); // 将Flutter页面内容转换为HTML字符串 final htmlContent = ''' <h1 style="font-size:24px; font-weight:bold;">HTML转可选中PDF</h1> <p style="font-size:16px; margin:16px 0;">这段文本由HTML渲染而来,支持选中复制。</p> <ul style="font-size:16px;"> <li>HTML列表项1</li> <li>HTML列表项2</li> </ul> '''; pdf.addPage( pw.Page( build: (pw.Context context) { return pw.Html( document: htmlContent, // 可选:自定义样式覆盖HTML中的样式 style: { 'h1': pw.TextStyle(color: PdfColors.blue), }, ); }, ), ); await Printing.sharePdf(bytes: await pdf.save(), filename: 'html_to_pdf.pdf'); }
避坑提示
- 绝对不要使用截图类插件(如
flutter_screenshot)将页面转为图片后插入PDF,这样生成的文本完全不可选中。 - 若使用自定义字体,必须将字体文件打包到项目中并加载到PDF,否则可能出现字体缺失导致的乱码。
- 复杂自定义Widget建议用方案一重新实现,确保PDF布局和文本的完整性。
内容的提问来源于stack exchange,提问作者Muhammet
相关产品推荐
相关产品推荐

