Easily Manage Multiple PDFs Simultaneously Using Flutter PDF Viewer

Calvince Moth - Dec 11 - - Dev Community

TL;DR: Effortlessly manage and navigate multiple PDF files simultaneously with the multi-tabbed Flutter PDF Viewer. This powerful tool provides a seamless experience, allowing users to switch between documents while enhancing productivity and streamlining workflows efficiently.

In document-processing applications, users often need to interact with multiple PDFs simultaneously for comparison, referencing, or multitasking.

While the Syncfusion Flutter PDF Viewer is fantastic for viewing individual documents, there are times when handling several PDFs in the same interface is essential. Users crave the flexibility to open and navigate different documents without losing context, like their scroll position or zoom level.

To meet this demand, we can enhance the Flutter PDF Viewer by implementing a tab-based interface. This approach allows users to switch between PDFs quickly and efficiently, creating a seamless experience akin to viewing multiple documents side by side.

In this blog, we’ll explore how to elevate your existing PDF viewing capabilities in Flutter by building a multi-tabbed PDF Viewer. This innovative solution empowers users to open and manage several PDFs effortlessly, making multitasking a breeze.

Advantages of multi-tabbed PDF Viewer

Here are some of the advantages of this approach:

  • Multi-document support: Open multiple PDFs, each in its own tab.
  • Quick navigation: Easily switch between different PDF documents using tabs.
  • Individual PDF controls: Each PDF Viewer instance maintains its own zoom, navigation, and rendering state.
  • Flexible file management: Easily open or close PDF files as needed, providing a flexible and tailored viewing experience.

Setting up the Flutter PDF Viewer

First, we need to install the Syncfusion Flutter PDF Viewer package by following these steps:

  1. Add the following code to your pubspec.yaml file to add the Syncfusion Flutter PDF Viewer dependency.
syncfusion_flutter_pdfviewer: ^xx.x.xx # Replace xx.x.xx with the latest version
Enter fullscreen mode Exit fullscreen mode

2.Next, you need to import the PDF Viewer package. Add the following import statement to your Dart file.

import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
Enter fullscreen mode Exit fullscreen mode

3.Once the package has been imported, initialize the SfPdfVieweras a child of any widget. For more details, refer to the getting started documentation.

Steps to implement the multi-tabbed feature in Flutter PDF Viewer

Step 1: Define the Tab bar and Tab controller

The TabBar widget will display tabs representing each PDF document, while TabBarView holds the actual PDF Viewer instances for each open document. Then, the TabController will manage tab switching and update the interface as new documents are opened or closed.

First, we’ll define the main widget ( PdfTabView ) to handle the tab setup, navigation, and interaction with PDF documents.

Refer to the following code example.

class PdfTabView extends StatefulWidget {
  const PdfTabView({super.key});

  @override
  State createState() => _PdfTabViewState();
}

class _PdfTabViewState extends State with TickerProviderStateMixin {
  late TabController _tabController; // Controller for managing tab navigation.
  late final List _openedFiles; // List to hold the opened PDF files.

  @override
  void initState() {
    super.initState(); // Call the super class's initState method.
    _openedFiles = []; // Initialize the list of opened PDF files.
    _tabController = TabController(length: _openedFiles.length, vsync: this); // Initialize the TabController with the current number of opened files.
  }

  @override
  void dispose() {
    _tabController.dispose(); // Dispose of the TabController to free resources.
    super.dispose(); // Call the super class's dispose method.
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: TabBarView(
        controller: _tabController, // Set the controller for the TabBarView.
        children: _openedFiles.map((PdfFile file) {
          // Create a list of PdfView widgets for each opened PDF file.
          return PdfView(
            key: file.key, // Unique key for the PdfView.
            bytes: file.bytes, // PDF file content as bytes.
          );
        }).toList(),
      ),
      appBar: AppBar(
        actions: [
          // Button to open a new PDF file.
          OutlinedButton(onPressed: _addNewTab, child: const Text('Open PDF')),
        ],
        bottom: TabBar(
          controller: _tabController, // Set the controller for the TabBar.
          tabs: _openedFiles.map((PdfFile file) {
            // Create a tab for each opened PDF file.
            return Tab(text: file.name);
          }).toList(),
        ),
      ),
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Step 2: Display the PDF file in the tab using Flutter PDF Viewer

In the TabBarView, each tab displays a PDF using the SfPdfViewer widget. Here, we’ll define a custom widget named PdfView to handle PDF rendering for each tab, as shown in the following code example.

class PdfView extends StatefulWidget {
  const PdfView({super.key, required this.bytes});

  // The PDF file as bytes
  final Uint8List bytes;

  @override
  State createState() => _PdfViewState();
}

class _PdfViewState extends State{

  @override
  Widget build(BuildContext context) {
    return SfPdfViewer.memory(
      widget.bytes,
    );
  }
}

Enter fullscreen mode Exit fullscreen mode

Step 3: Opening a new PDF file in its own tab

When a user selects a new PDF file, we create a new tab to display it. This allows users to dynamically open new PDFs in their own tabs, enhancing the multitasking experience.

Refer to the following code example.

Future _addNewTab() async {
// Prompt the user to pick a PDF file and retrieve it as bytes.
  final Uint8List? bytes = await _pickPdf();

 // If a file was selected, add it to the open files and update the tab controller.
  if (bytes != null) {
    setState(() {
      _openedFiles.add(PdfFile('fileName', bytes, UniqueKey()));
      _tabController = TabController(
        length: _openedFiles.length,
        vsync: this,
        initialIndex: _openedFiles.length - 1,
      );
    });
  }
}
Enter fullscreen mode Exit fullscreen mode

Step 4: Closing a PDF file

To remove a tab corresponding to a closed PDF file and update the tab controller, we’ll define a method that manages this functionality.

When a user closes a tab, we ensure that the corresponding PDF file is removed from the list and that the tab controller is updated accordingly.

Refer to the following code example.

void _removeTab(int index) {
  // Remove the PDF file at the specified index.
  _openedFiles.removeAt(index);

  // Dispose of the previous TabController to free resources.
  _tabController.dispose();

  // Update the TabController with the new length of opened files.
  setState(() {
    _tabController = TabController(
      length: _openedFiles.length,
      vsync: this,
    );
  });
}
Enter fullscreen mode Exit fullscreen mode

Step 5: Preserving the PDF Viewer state

To ensure that the PDF Viewer retains its state (such as zoom level and scroll position) when switching between tabs, we utilize the AutomaticKeepAliveClientMixin. This approach prevents the SfPdfViewer widget from being disposed of when changing tabs, maintaining the user’s viewing experience.

Refer to the following code example.

class _PdfViewState extends State with AutomaticKeepAliveClientMixin {
  @override
  bool get wantKeepAlive => true;

  @override
  Widget build(BuildContext context) {
    // Call super.build to maintain the keep-alive state.
    super.build(context);
    return SfPdfViewer.memory(
      widget.bytes,
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

That’s it! Now, we’ve implemented a multi-tab PDF Viewer in Flutter that allows users to open multiple PDF files seamlessly, manage tabs, and preserve the viewer state for an enhanced experience.

Refer to the following output GIF image.


Multi-tabbed Flutter PDF Viewer

GitHub reference

For more details, refer to the multi-tabbed Flutter PDF Viewer GitHub demo.

To run the demo, please follow these steps:

  1. Download the demo from the GitHub repository and run the app.
  2. A default PDF file will be displayed and loaded from the Assets folder.
  3. To add a new PDF file, click the Open PDF button located at the top right. The document will open in a new tab.
  4. To close a PDF file, click the close option available in the respective tab.

Conclusion

Thanks for reading! Following this approach, you can build a multi-tabbed Flutter PDF Viewer that allows users to manage and view multiple PDF documents simultaneously. This solution not only makes it easier to work across multiple PDFs but also provides an intuitive and smooth experience by maintaining states across tabs and allowing dynamic document management.

If you’re an existing Syncfusion user, you can download the latest version of Essential Studio® from the License and Downloads page. For new users, we offer a 30-day free trial so you can explore these powerful features yourself.

If you need any help, don’t hesitate to reach out through our support forum, support portal, or feedback portal. We’re always here to assist you!

Related Blogs

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .