Flutter plugin to render PDF and show a PDF file on Web, MacOs 10.11+, Android 5.0+ and iOS.
demo


Installation
In your flutter project add the dependency:
dependencies: native_pdf_view: any
For web add lines in index.html before importing main.dart.js:
<script src="//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.min.js"></script> <script type="text/javascript"> pdfjsLib.GlobalWorkerOptions.workerSrc = "//cdnjs.cloudflare.com/ajax/libs/pdf.js/2.4.456/pdf.worker.min.js"; </script>
Usage example
It very simple!
import 'package:native_pdf_view/native_pdf_view.dart'; final pdfController = PdfController( document: PdfDocument.openAsset('assets/sample.pdf'), ); Widget pdfView() => PdfView( controller: pdfController, );
Api
PdfController
Parameter | Description | Default |
---|---|---|
document | The document to be displayed | – |
initialPage | The page to show when first creating the [PdfView] | 1 |
viewportFraction | The fraction of the viewport that each page should occupy. | 1.0 |
PdfView
Parameter | Description | Default |
---|---|---|
controller | Pages control. See page control and additional pdf info | – |
onPageChanged | Called whenever the page in the center of the viewport changes. See Document callbacks | – |
onDocumentLoaded | Called when a document is loaded. See Document callbacks | – |
onDocumentError | Called when a document loading error. Exception is passed in the attributes | – |
documentLoader | Widget showing when pdf document loading | SizedBox() |
pageLoader | Widget showing when pdf page loading | SizedBox() |
builder | Callback called to render a widget for each page. See custom page builder | Default builder |
errorBuilder | Show document loading error message inside PdfView | Centered error text |
renderer | Custom PdfRenderer library options. See custom renderer options | width: page.width * 2 height: page.height * 2 format: PdfPageFormat.JPEG backgroundColor: ‘#ffffff’ |
scrollDirection | Page turning direction | Axis.horizontal |
physics | How the widgets should respond to user input | – |
pageSnapping | Set to false for mouse wheel scroll on web | true |
Additional examples
Open another document
pdfController.openDocument(PdfDocument.openAsset('assets/sample.pdf'));
Page control:
// 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);
Additional pdf info:
// Actual showed page pdfController.page; // Count of all pages in document pdfController.pagesCount;
Document callbacks
int _actualPageNumber = 0, _allPagesCount = 0; PdfView( controller: pdfController, onDocumentLoaded: (document) { setState(() { _allPagesCount = document.pagesCount; }); }, onPageChanged: (page) { setState(() { _actualPageNumber = page; }); }, ); /// Now you can use these values to display the reading status of the document. Text('Read: $_actualPageNumber of $_allPagesCount');
Custom renderer options
PdfView( controller: pdfController, renderer: (PdfPage page) => page.render( width: page.width * 2, height: page.height * 2, format: PdfPageFormat.JPEG, backgroundColor: '#FFFFFF', ), );
Custom page builder:
PdfView( controller: pdfController, document: snapshot.data, pageBuilder: ( PdfPageImage pageImage, bool isCurrentIndex, AnimationController animationController, ) { // Double tap scales final List<double> _doubleTapScales = <double>[1.0, 2.0, 3.0] // Double tap animation Animation<double> _doubleTapAnimation; void Function() _animationListener; Widget image = ExtendedImage.memory( pageImage.bytes, key: Key(pageImage.hashCode.toString()), fit: BoxFit.contain, mode: ExtendedImageMode.gesture, initGestureConfigHandler: (_) => GestureConfig( minScale: 1, maxScale: 3.0, animationMinScale: .75, animationMaxScale: 3.0, speed: 1, inertialSpeed: 100, inPageView: true, initialScale: 1.0, cacheGesture: false, ), onDoubleTap: (ExtendedImageGestureState state) { final pointerDownPosition = state.pointerDownPosition; final begin = state.gestureDetails.totalScale; double end; _doubleTapAnimation?.removeListener(_animationListener); animationController ..stop() ..reset(); if (begin == _doubleTapScales[0]) { end = _doubleTapScales[1]; } else { if (begin == _doubleTapScales[1]) { end = _doubleTapScales[2]; } else { end = _doubleTapScales[0]; } } _animationListener = () { //print(_animation.value); state.handleDoubleTap( scale: _doubleTapAnimation.value, doubleTapPosition: pointerDownPosition); }; _doubleTapAnimation = animationController .drive(Tween<double>(begin: begin, end: end)) ..addListener(_animationListener); animationController.forward(); }, ); if (isCurrentIndex) { image = Hero( tag: 'pdf_view' + pageImage.pageNumber.toString(), child: image, ); } return image; }, );
Rendering additional info
On Web
This plugin uses the PDF.js
On Android
This plugin uses the Android native PdfRenderer
On Ios & MacOs
This plugin uses the IOS native CGPDFPage