native_pdf_view 3.5.2 copy "native_pdf_view: ^3.5.2" to clipboard
native_pdf_view: ^3.5.2 copied to clipboard

outdated

Flutter plugin to render PDF files on Web, MacOS, Android and iOS.

native_pdf_view #

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

Showcase #

Live Screenshot

Getting Started #

In your flutter project add the dependency:

pub package

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.builder(
  controller: pdfController,
  document: snapshot.data,
  builder: (
    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 PDFKit