flutter_native_pdf_viewer 0.1.7
flutter_native_pdf_viewer: ^0.1.7 copied to clipboard
A Flutter plugin for viewing PDF files with native implementation supporting annotations, search, and zoom capabilities.
example/lib/main.dart
import 'package:flutter/material.dart';
import 'package:flutter_native_pdf_viewer/flutter_native_pdf_viewer.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'PDF Viewer Example',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const ExampleScreen(),
);
}
}
class ExampleScreen extends StatefulWidget {
const ExampleScreen({super.key});
@override
State<ExampleScreen> createState() => _ExampleScreenState();
}
class _ExampleScreenState extends State<ExampleScreen> {
final String pdfUrl =
'https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf';
String? searchQuery;
int currentMatchIndex = 0;
int totalMatches = 0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('PDF Viewer Example'),
actions: [
IconButton(
icon: const Icon(Icons.search),
onPressed: _showSearchDialog,
),
],
),
body: Stack(
children: [
NativePdfView(
url: pdfUrl,
searchQuery: searchQuery,
currentMatchIndex: currentMatchIndex,
onSearchResultsChanged: (total, error) {
setState(() {
totalMatches = total;
});
},
),
if (searchQuery != null && totalMatches > 0)
Positioned(
top: 16,
left: 0,
right: 0,
child: Center(
child: Container(
padding:
const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration(
color: Colors.black87,
borderRadius: BorderRadius.circular(24),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
Text(
'${currentMatchIndex + 1} / $totalMatches',
style: const TextStyle(color: Colors.white),
),
const SizedBox(width: 16),
IconButton(
icon:
const Icon(Icons.arrow_upward, color: Colors.white),
onPressed: () {
setState(() {
if (currentMatchIndex > 0) {
currentMatchIndex--;
} else {
currentMatchIndex = totalMatches - 1;
}
});
},
),
IconButton(
icon: const Icon(Icons.arrow_downward,
color: Colors.white),
onPressed: () {
setState(() {
if (currentMatchIndex < totalMatches - 1) {
currentMatchIndex++;
} else {
currentMatchIndex = 0;
}
});
},
),
IconButton(
icon: const Icon(Icons.close, color: Colors.white),
onPressed: () {
setState(() {
searchQuery = null;
totalMatches = 0;
});
},
),
],
),
),
),
),
],
),
);
}
void _showSearchDialog() {
final textController = TextEditingController();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('Search Text'),
content: TextField(
controller: textController,
autofocus: true,
decoration: const InputDecoration(
hintText: 'Enter text to search',
border: OutlineInputBorder(),
),
),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () {
final query = textController.text.trim();
if (query.isNotEmpty) {
setState(() {
searchQuery = query;
currentMatchIndex = 0;
});
Navigator.pop(context);
}
},
child: const Text('Search'),
),
],
),
);
}
}