How to dynamically add internal navigation to pdf in flutter

Viewed 212

I am working on a flutter app which generates PDF files in flutter using pdf library (https://pub.dev/packages/pdf/changelog). I need to create a pdf file which has a table of contents. They should be linked with the actual content and should navigate to their respective pages when clicked on it. I couldn't find any documentation online for doing this using the pdf library. The PDF is going to be written to a file so PDF Viewers in flutter are not useful for me either. Can someone please help me out

[UPDATE] I tried using Link and Anchor in my code. But it doesnt seem to work. Am i doing something wrong?

reportView(context) async {
  final Document pdf = Document();

  final ByteData fontData =
      await rootBundle.load("assets/fonts/Open_Sans/OpenSans-Regular.ttf");

  final Font ttf = Font.ttf(fontData);
  final textStyle = TextStyle(font: ttf);

  final Wrap item = Wrap(children: await _buildPdfBlock(textStyle));

  pdf.addPage(
    MultiPage(
      pageFormat:
          PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
      crossAxisAlignment: CrossAxisAlignment.start,
      build: (Context context) => [item],
    ),
  );

  _index(
    context,
    pdf,
    textStyle,
  );

  _contents(context, pdf, textStyle);

  final String dir = (await getApplicationDocumentsDirectory()).path;
  final String path = '$dir/App_' + '.pdf';
  final File file = File(path);
  print(path);
  await file.writeAsBytes(pdf.save());
  await Share.shareFiles([path]);
}

Future<List<Widget>> _buildPdfBlock(TextStyle textStyle) async {
  List<Widget> list = [];
  Column column = Column(
      mainAxisAlignment: MainAxisAlignment.start,
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Header(level: 1, child: Text("PDF Generation", style: textStyle)),
        Text("Hello World", style: textStyle)
      ]);
  list.add(column);
  return list;
}

void _index(dynamic context, Document pdf, TextStyle textStyle) {
  List<Widget> indexList = [];
  var indexNumber = 1;
  for (var i = indexNumber; i < 10; i++) {
    Text indexText = Text(indexNumber.toString() + ". " + "Hello$indexNumber",
        style: textStyle);
    Link(
        child: indexText,
        destination: indexNumber.toString() + ". " + "Hello$indexNumber");
    indexList.add(indexText);

    indexNumber++;
  }
  pdf.addPage(
    MultiPage(
      pageFormat:
          PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
      crossAxisAlignment: CrossAxisAlignment.start,
      build: (Context context) => indexList,
    ),
  );
}

void _contents(dynamic context, Document pdf, TextStyle textStyle) {
  List<Widget> contentList = [];
  var contentNumber = 1;
  for (var i = contentNumber; i < 10; i++) {
    Header contentIndex = Header(
        child: Text(contentNumber.toString() + ". " + "Hello$contentNumber",
            style: textStyle));
    Text content = Text("               " +
        loremIpsum(words: 60, paragraphs: 3, initWithLorem: true));

    Anchor(
        name: contentNumber.toString() + ". " + "Hello$contentNumber",
        child: contentIndex);
    contentList.add(contentIndex);
    contentList.add(content);

    contentNumber++;
  }
  pdf.addPage(
    MultiPage(
      pageFormat:
          PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
      crossAxisAlignment: CrossAxisAlignment.start,
      build: (Context context) => contentList,
    ),
  );
}

[UPDATE] Its working now, my implementation was wrong. Thanks for the help

1 Answers

You can create such a page with dart_pdf in code using Anchor and Link inside the PDF:

First create an Anchor on the page to which you want to link to:

Anchor(name: 'my_first_anchor'),

and then you can refer to that anchor in your table of contents like that:

Link(destination: 'my_first_anchor'),

Obviously Anchor names have to be unique.

Related