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.
Here are some of the advantages of this approach:
First, we need to install the Syncfusion Flutter PDF Viewer package by following these steps:
syncfusion_flutter_pdfviewer: ^xx.x.xx # Replace xx.x.xx with the latest version
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
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(), ), ), ); } }
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, ); } }
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, ); }); } }
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, ); }); }
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, ); } }
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.
For more details, refer to the multi-tabbed Flutter PDF Viewer GitHub demo.
To run the demo, please follow these steps:
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!