ecp_file_view 4.0.0
ecp_file_view: ^4.0.0 copied to clipboard
A file viewer plugin for Flutter, support local file and network link of Android, iOS.
example/lib/main.dart
import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:ecp_file_view/ecp_file_view.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:path_provider/path_provider.dart';
import 'page_local_file_viewer.dart';
void main() async {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return const MaterialApp(
localizationsDelegates: <LocalizationsDelegate<dynamic>>[
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
ViewerLocalizationsDelegate.delegate,
],
supportedLocales: [Locale('en', 'US'), Locale('zh', 'CN')],
debugShowCheckedModeBanner: false,
home: HomePage(),
);
}
}
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
/// 本地文件(assets/files 目录)
final List<String> localFiles = [
'docx.docx',
'doc.doc',
'xlsx.xlsx',
'xls.xls',
'pptx.pptx',
'ppt.ppt',
'pdf.pdf',
'txt.txt',
];
/// 在线大文档测试链接(非 GitHub 源,国内可访问,均已验证)
final List<String> networkFiles = [
// txt 2.2MB(Unicode 官方字符表)
'https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt',
// pdf 10.5MB(华为《迈向智能世界》计算白皮书)
'https://www-file.huawei.com/-/media/corp2020/pdf/giv/striding-towards-the-intelligent-world/the_intelligent_world_computing_cn.pdf?la=zh',
// doc 6.2MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/document/Bug61268.doc',
// docx 3.0MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/document/saut_page.docx',
// xls 4.7MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/spreadsheet/ex45698-22488.xls',
// xlsx 2.9MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/spreadsheet/LIBRE_OFFICE-116306-0.xlsx',
// ppt 3.3MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/slideshow/customGeo.ppt',
// pptx 2.3MB(Apache POI 测试数据,Gitee 镜像)
'https://gitee.com/apache/poi/raw/trunk/test-data/slideshow/KEY02.pptx',
];
@override
Widget build(BuildContext context) {
return DefaultTabController(
length: 2,
child: Scaffold(
appBar: AppBar(
title: const Text('File View'),
bottom: const TabBar(tabs: [Tab(text: '本地'), Tab(text: '网络')]),
),
body: TabBarView(
children: [_buildLocalListWidget(), _buildNetworkListWidget()],
),
),
);
}
/// 本地文件列表
Widget _buildLocalListWidget() {
return ListView.builder(
itemCount: localFiles.length,
itemBuilder: (context, index) {
String name = localFiles[index];
String type = FileTool.getFileType(name);
return _buildListItem(
name,
() => onLocalTap(type, 'assets/files/$name'),
);
},
);
}
/// 网络文件列表
Widget _buildNetworkListWidget() {
return ListView.builder(
itemCount: networkFiles.length,
itemBuilder: (context, index) {
String url = networkFiles[index];
return _buildListItem(
_getDisplayName(url),
() => onNetworkTap(url),
);
},
);
}
/// 从链接中提取显示名称(去掉 query 参数)
String _getDisplayName(String url) {
var name = FileTool.getFileName(url);
int queryIndex = name.indexOf('?');
if (queryIndex > -1) {
name = name.substring(0, queryIndex);
}
return name;
}
/// 通用列表项
Widget _buildListItem(String title, VoidCallback onTap) {
return Container(
margin: const EdgeInsets.only(top: 10.0),
padding: const EdgeInsets.symmetric(horizontal: 15.0),
child: ElevatedButton(
onPressed: onTap,
child: Text(title),
),
);
}
Future onLocalTap(String type, String assetPath) async {
String filePath = await setFilePath(type, assetPath);
if (!await asset2Local(type, assetPath)) {
return;
}
Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
return LocalFileViewerPage(filePath: filePath);
}));
}
Future onNetworkTap(String downloadUrl) async {
// 优先使用链接中的文件名(含扩展名),便于预览时识别文档类型
var name = _getDisplayName(downloadUrl);
if (!name.contains('.')) {
name = 'test.txt';
}
Navigator.of(context).push(MaterialPageRoute(builder: (ctx) {
return NetworkFileViewer(url: downloadUrl, name: name);
}));
}
Future asset2Local(String type, String assetPath) async {
String filePath = await setFilePath(type, assetPath);
File file = File(filePath);
if (fileExists(filePath)) {
await file.delete();
}
await file.create(recursive: true);
debugPrint("文件路径 -> ${file.path}");
ByteData bd = await rootBundle.load(assetPath);
await file.writeAsBytes(bd.buffer.asUint8List(), flush: true);
return true;
}
Future setFilePath(String type, String assetPath) async {
final directory = await getTemporaryDirectory();
return "${directory.path}/fileview/${base64.encode(utf8.encode(assetPath))}.$type";
}
bool fileExists(String filePath) => File(filePath).existsSync();
}