PDFx
Flutter 在 Web、macOS 10.11+、Android 5.0+、iOS 和 Windows 上渲染和显示 PDF 文档。
包含 2 个 API
renderer处理 PDF 文档、页面,将页面渲染为图像viewer一组用于显示渲染结果的 Flutter 小部件和控制器
展示
| PdfViewPinch | PdfView |
|---|---|
![]() |
![]() |
入门
在您的 Flutter 项目中添加依赖项
flutter pub add pdfx
对于 Web 运行工具,自动将 pdfjs 库 (CDN) 添加到 index.html 中
flutter pub run pdfx:install_web
对于 Windows 运行工具,自动将 pdfium 版本属性的覆盖添加到 CMakeLists.txt 文件中
flutter pub run pdfx:install_windows
使用示例
import 'package:pdf_view/pdfx.dart';
final pdfPinchController = PdfControllerPinch(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
// Pdf view with re-render pdf texture on zoom (not loose quality on zoom)
// Not supported on windows
PdfViewPinch(
controller: pdfPinchController,
);
//-- or --//
final pdfController = PdfController(
document: PdfDocument.openAsset('assets/sample.pdf'),
);
// Simple Pdf view with one render of page (loose quality on zoom)
PdfView(
controller: pdfController,
);
Viewer API
PdfController & PdfControllerPinch
| 参数 | 描述 | 默认值 |
|---|---|---|
| document | 要显示的文档 | – |
| initialPage | 创建 [PdfView] 时显示的页面 | 1 |
| viewportFraction | 每个页面应占据的视口比例。 | 1.0 |
PdfView & PdfViewPinch
| 参数 | 描述 | PdfViewPinch / PdfView |
|---|---|---|
| 控制器 | 页面控制。请参阅 页面控制 和 其他 PDF 信息 | + / + |
| onPageChanged | 每当视口中心的页面发生变化时调用。请参阅 文档回调 | + / + |
| onDocumentLoaded | 文档加载时调用。请参阅 文档回调 | + / + |
| onDocumentError | 文档加载错误时调用。异常在属性中传递 | + / + |
| builders | 一组 PDF 视图构建器。请参阅 自定义构建器 | + / + |
| scrollDirection | 翻页方向 | + / + |
| renderer | 自定义 PdfRenderer 选项。请参阅 自定义渲染器选项 | – / + |
| pageSnapping | 在 Web 上进行鼠标滚轮滚动时设置为 false | – / + |
| physics | 小部件如何响应用户输入 | – / + |
| padding | 每个页面的内边距。 | + / – |
PdfViewBuilders & PdfViewPinchBuilders
| 参数 | 描述 | PdfViewPinchBuilders / PdfViewBuilders |
|---|---|---|
| 选项 | 构建器的附加选项 | + / + |
| documentLoaderBuilder | PDF 文档加载时显示的窗口小部件 | + / + |
| pageLoaderBuilder | PDF 页面加载时显示的窗口小部件 | + / + |
| errorBuilder | 显示文档加载错误消息 | + / + |
| builder | 用于动画 PDF 加载状态的根视图构建器 | + / + |
| pageBuilder | 调用回调为每个页面渲染窗口小部件。请参阅 自定义页面构建器 | – / + |
其他示例
打开另一个文档
pdfController.openDocument(PdfDocument.openAsset('assets/sample.pdf'));
页面控制
// Jump to specified page
pdfController.jumpTo(3);
// Animate to specified page
_pdfController.animateToPage(3, duration: Duration(milliseconds: 250), curve: Curves.ease);
// Animate to next page
_pdfController.nextPage(duration: Duration(milliseconds: 250), curve: Curves.easeIn);
// Animate to previous page
_pdfController.previousPage(duration: Duration(milliseconds: 250), curve: Curves.easeOut);
其他 PDF 信息
// Actual showed page
pdfController.page;
// Count of all pages in document
pdfController.pagesCount;
文档回调
PdfView(
controller: pdfController,
onDocumentLoaded: (document) {},
onPageChanged: (page) {},
);
显示实际页码和总页数
PdfPageNumber(
controller: _pdfController,
// When `loadingState != PdfLoadingState.success` `pagesCount` equals null_
builder: (_, state, loadingState, pagesCount) => Container(
alignment: Alignment.center,
child: Text(
'$page/${pagesCount ?? 0}',
style: const TextStyle(fontSize: 22),
),
),
)
自定义渲染器选项
PdfView(
controller: pdfController,
renderer: (PdfPage page) => page.render(
width: page.width * 2,
height: page.height * 2,
format: PdfPageImageFormat.jpeg,
backgroundColor: '#FFFFFF',
),
);
自定义构建器
// Need static methods for builders arguments
class SomeWidget {
static Widget builder(
BuildContext context,
PdfViewPinchBuilders builders,
PdfLoadingState state,
WidgetBuilder loadedBuilder,
PdfDocument? document,
Exception? loadingError,
) {
final Widget content = () {
switch (state) {
case PdfLoadingState.loading:
return KeyedSubtree(
key: const Key('pdfx.root.loading'),
child: builders.documentLoaderBuilder?.call(context) ??
const SizedBox(),
);
case PdfLoadingState.error:
return KeyedSubtree(
key: const Key('pdfx.root.error'),
child: builders.errorBuilder?.call(context, loadingError!) ??
Center(child: Text(loadingError.toString())),
);
case PdfLoadingState.success:
return KeyedSubtree(
key: Key('pdfx.root.success.${document!.id}'),
child: loadedBuilder(context),
);
}
}();
final defaultBuilder =
builders as PdfViewPinchBuilders<DefaultBuilderOptions>;
final options = defaultBuilder.options;
return AnimatedSwitcher(
duration: options.loaderSwitchDuration,
transitionBuilder: options.transitionBuilder,
child: content,
);
}
static Widget transitionBuilder(Widget child, Animation<double> animation) =>
FadeTransition(opacity: animation, child: child);
static PhotoViewGalleryPageOptions pageBuilder(
BuildContext context,
Future<PdfPageImage> pageImage,
int index,
PdfDocument document,
) =>
PhotoViewGalleryPageOptions(
imageProvider: PdfPageImageProvider(
pageImage,
index,
document.id,
),
minScale: PhotoViewComputedScale.contained * 1,
maxScale: PhotoViewComputedScale.contained * 3.0,
initialScale: PhotoViewComputedScale.contained * 1.0,
heroAttributes: PhotoViewHeroAttributes(tag: '${document.id}-$index'),
);
}
PdfViewPinch(
controller: pdfPinchController,
builders: PdfViewPinchBuilders<DefaultBuilderOptions>(
options: const DefaultBuilderOptions(
loaderSwitchDuration: const Duration(seconds: 1),
transitionBuilder: SomeWidget.transitionBuilder,
),
documentLoaderBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
pageLoaderBuilder: (_) =>
const Center(child: CircularProgressIndicator()),
errorBuilder: (_, error) => Center(child: Text(error.toString())),
builder: SomeWidget.builder,
),
)
PdfView(
controller: pdfController,
builders: PdfViewBuilders<DefaultBuilderOptions>(
// All from `PdfViewPinch` and:
pageBuilder: SomeWidget.pageBuilder,
),
);
渲染器 API
PdfDocument
| 参数 | 描述 | 默认值 |
|---|---|---|
| sourceName | toString 方法需要。包含打开文档的方法(文件、数据或资产) | – |
| id | 文档唯一 ID。打开文档时生成。 | – |
| pagesCount | 文档中的总页数。从 1 开始。 | – |
| isClosed | 文档是否已关闭 | – |
本地文档打开
// From assets (Android, Ios, MacOs, Web)
final document = await PdfDocument.openAsset('assets/sample.pdf')
// From file (Android, Ios, MacOs)
final document = await PdfDocument.openFile('path/to/file/on/device')
// From data (Android, Ios, MacOs, Web)
final document = await PdfDocument.openData((FutureOr<Uint8List>) data)
网络文档打开
安装 [network_file] 包(支持所有平台)
flutter pub add internet_file
并使用它
import 'package:internet_file/internet_file.dart';
PdfDocument.openData(InternetFile.get('https://github.com/ScerIO/packages.flutter/raw/fd0c92ac83ee355255acb306251b1adfeb2f2fd6/packages/native_pdf_renderer/example/assets/sample.pdf'))
打开页面
final page = document.getPage(pageNumber); // Starts from 1
关闭文档
document.close();
PdfPage
| 参数 | 描述 | 默认值 |
|---|---|---|
| document | 父文档 | Parent |
| id | 页面唯一 ID。渲染和关闭页面需要。打开页面时生成。 | – |
| width | 页面源宽度(以像素为单位),整数 | – |
| 高度 | 页面源高度(以像素为单位),整数 | – |
| isClosed | 页面是否已关闭 | 假 |
渲染图像
final pageImage = page.render(
// rendered image width resolution, required
width: page.width * 2,
// rendered image height resolution, required
height: page.height * 2,
// Rendered image compression format, also can be PNG, WEBP*
// Optional, default: PdfPageImageFormat.PNG
// Web not supported
format: PdfPageImageFormat.JPEG,
// Image background fill color for JPEG
// Optional, default '#ffffff'
// Web not supported
backgroundColor: '#ffffff',
// Crop rect in image for render
// Optional, default null
// Web not supported
cropRect: Rect.fromLTRB(left, top, right, bottom),
);
PdfPageImage
| 参数 | 描述 | 默认值 |
|---|---|---|
| id | 页面唯一 ID。渲染和关闭页面需要。渲染页面时生成。 | – |
| pageNumber | 页码。第一页为 1。 | – |
| width | 渲染区域的宽度(以像素为单位),整数 | – |
| 高度 | 渲染区域的高度(以像素为单位),整数 | – |
| bytes | 渲染的图像结果,Uint8List | – |
| format | 渲染的图像压缩格式,Web 版始终为 PNG | PdfPageImageFormat.PNG |
关闭页面
在打开新页面之前,Android 会要求关闭旧页面。如果未执行此操作,应用程序可能会因错误而崩溃
page.close();
* PdfPageImageFormat.WEBP 仅在 Android 上支持
渲染附加信息
在 Web 上
此插件使用了 PDF.js
在 Android 上
此插件使用了 Android 原生的 PdfRenderer
在 iOS & macOS 上
此插件使用了 iOS & macOS 原生的 CGPDFPage
在 Windows 上
此插件使用了 PDFium

