说明
flutter_full_pdf_viewer 可以实现从网络上下载 pdf 文件并且显示出来。
包地址:flutter_full_pdf_viewer: ^1.0.6
使用方法
1.在 pubspec.yaml 文件中添加如下的包:
dependencies:
# pdf 阅读器
flutter_full_pdf_viewer: ^1.0.6
# 获取系统目录,因为从网络获取的pdf文件,需要保存到手机,所以需要用到这个包
path_provider: ^1.5.0
2.官方demo:
import \'dart:async\';
import \'dart:io\';
import \'package:flutter/foundation.dart\';
import \'package:flutter/material.dart\';
import \'package:flutter_full_pdf_viewer/full_pdf_viewer_scaffold.dart\';
import \'package:path_provider/path_provider.dart\';
void main() {
runApp(MaterialApp(
title: \'Plugin example app\',
home: MyApp(),
));
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
String pathPDF = "";
@override
void initState() {
super.initState();
createFileOfPdfUrl().then((f) {
setState(() {
pathPDF = f.path;
print(pathPDF);
});
});
}
Future<File> createFileOfPdfUrl() async {
final url = "http://africau.edu/images/default/sample.pdf";
final filename = url.substring(url.lastIndexOf("/") + 1);
var request = await HttpClient().getUrl(Uri.parse(url));
var response = await request.close();
var bytes = await consolidateHttpClientResponseBytes(response);
String dir = (await getApplicationDocumentsDirectory()).path;
File file = new File(\'$dir/$filename\');
await file.writeAsBytes(bytes);
return file;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text(\'Plugin example app\')),
body: Center(
child: RaisedButton(
child: Text("Open PDF"),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(builder: (context) => PDFScreen(pathPDF)),
),
),
),
);
}
}
/// /////////////////////////// 显示 pdf 图文件 //////////////////////////// ///
class PDFScreen extends StatelessWidget {
String pathPDF = "";
PDFScreen(this.pathPDF);
@override
Widget build(BuildContext context) {
return PDFViewerScaffold(
appBar: AppBar(
title: Text("Document"),
actions: <Widget>[
IconButton(
icon: Icon(Icons.share),
onPressed: () {},
),
],
),
path: pathPDF,
);
}
}
3.官方demo 显示效果:
源码解析
主要有两个源码文件,分别是 full_pdf_viewer_plugin.dart 和 full_pdf_viewer_scaffold.dart 文件
1.full_pdf_viewer_plugin.dart
import \'dart:async\';
import \'dart:ui\';
import \'package:flutter/material.dart\';
import \'package:flutter/services.dart\';
enum PDFViewState { shouldStart, startLoad, finishLoad }
class PDFViewerPlugin {
final _channel = const MethodChannel("flutter_full_pdf_viewer");
static PDFViewerPlugin _instance;
factory PDFViewerPlugin() => _instance ??= new PDFViewerPlugin._();
PDFViewerPlugin._() {
_channel.setMethodCallHandler(_handleMessages);
}
final _onDestroy = new StreamController<Null>.broadcast();
Stream<Null> get onDestroy => _onDestroy.stream;
Future<Null> _handleMessages(MethodCall call) async {
switch (call.method) {
case \'onDestroy\':
_onDestroy.add(null);
break;
}
}
Future<Null> launch(String path, {Rect rect}) async {
final args = <String, dynamic>{\'path\': path};
if (rect != null) {
args[\'rect\'] = {
\'left\': rect.left,
\'top\': rect.top,
\'width\': rect.width,
\'height\': rect.height
};
}
await _channel.invokeMethod(\'launch\', args);
}
/// Close the PDFViewer
/// Will trigger the [onDestroy] event
Future close() => _channel.invokeMethod(\'close\');
/// adds the plugin as ActivityResultListener
/// Only needed and used on Android
Future registerAcitivityResultListener() =>
_channel.invokeMethod(\'registerAcitivityResultListener\');
/// removes the plugin as ActivityResultListener
/// Only needed and used on Android
Future removeAcitivityResultListener() =>
_channel.invokeMethod(\'removeAcitivityResultListener\');
/// Close all Streams
void dispose() {
_onDestroy.close();
_instance = null;
}
/// resize PDFViewer
Future<Null> resize(Rect rect) async {
final args = {};
args[\'rect\'] = {
\'left\': rect.left,
\'top\': rect.top,
\'width\': rect.width,
\'height\': rect.height
};
await _channel.invokeMethod(\'resize\', args);
}
}
2.full_pdf_viewer_scaffold.dart
其实笔者在实际的使用过程中,是把它提取出来使用的,这样做是为了可以修改源码,让他符合自己的使用场景。当pdf不是全屏显示时,就会遇到状态栏、导航栏高度的问题,可以看笔者写的这篇文章。
import \'dart:async\'; import \'package:flutter/foundation.dart\'; import \'package:flutter/material.dart\'; import \'package:flutter_full_pdf_viewer/full_pdf_viewer_plugin.dart\'; class PDFViewerScaffold extends StatefulWidget { final PreferredSizeWidget appBar; final String path; final bool primary; const PDFViewerScaffold({ Key key, this.appBar, @required this.path, this.primary = true, }) : super(key: key); @override _PDFViewScaffoldState createState() => new _PDFViewScaffoldState(); } class _PDFViewScaffoldState extends State<PDFViewerScaffold> { final pdfViwerRef = new PDFViewerPlugin(); Rect _rect; Timer _resizeTimer; @override void initState() { super.initState(); pdfViwerRef.close(); } @override void dispose() { super.dispose(); pdfViwerRef.close(); pdfViwerRef.dispose(); } @override Widget build(BuildContext context) { if (_rect == null) { _rect = _buildRect(context); pdfViwerRef.launch( widget.path, rect: _rect, ); } else { final rect = _buildRect(context); if (_rect != rect) { _rect = rect; _resizeTimer?.cancel(); _resizeTimer = new Timer(new Duration(milliseconds: 300), () { pdfViwerRef.resize(_rect); }); } } return new Scaffold( appBar: widget.appBar, body: const Center(child: const CircularProgressIndicator())); } Rect _buildRect(BuildContext context) { final fullscreen = widget.appBar == null; final mediaQuery = MediaQuery.of(context); final topPadding = widget.primary ? mediaQuery.padding.top : 0.0; final top = fullscreen ? 0.0 : widget.appBar.preferredSize.height + topPadding; var height = mediaQuery.size.height - top; if (height < 0.0) { height = 0.0; } return new Rect.fromLTWH(0.0, top, mediaQuery.size.width, height); } }
原文:http://www.luyixian.cn/news_show_398459.aspx