前言
简单学习一下几个比较好用的文件读取库
video_player
简介
用于视频播放
官方文档
https://pub-web.flutter-io.cn/packages/video_player
安装
flutter pub add video_player
加载网络视频
class _MyHomePageState extends State<MyHomePage> {
// 控制器
late VideoPlayerController _controller;
// 初始化
@override
void initState() {
super.initState();
// 加载网络视频
_controller = VideoPlayerController.networkUrl(
Uri.parse('https://www.tujuyun.com/pixabay/video/VideoBig/1024927/4006.mp4'))
..initialize().then((_) {
setState(() {});
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: _controller.value.isInitialized // 判断是否已经加载完成
? AspectRatio(
// 设置视频播放的宽高比
aspectRatio: _controller.value.aspectRatio,
child: VideoPlayer(_controller),
)
: Container(),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
setState(() {
_controller.value.isPlaying // 判断是否是在播放中
? _controller.pause() //暂停
: _controller.play(); // 播放
});
},
child: Icon(
_controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
),
),
);
}
}
加载本地视频
_controller = VideoPlayerController.asset('lib/assets/video/3998.mp4')
..initialize().then((_) {
setState(() {});
});
设置倍速和进度条
Center(
child: _controller.value.isInitialized // 判断是否已经加载完成
? AspectRatio(
// 设置视频播放的宽高比
aspectRatio: _controller.value.aspectRatio,
child: Stack(
alignment: Alignment.bottomCenter,
children: <Widget>[
// 视频播放器
VideoPlayer(_controller),
// 设置倍速
Row(
children: [
ElevatedButton(
onPressed: () {
_controller.setPlaybackSpeed(1);
},
child: const Text("1倍速")),
ElevatedButton(
onPressed: () {
_controller.setPlaybackSpeed(5);
},
child: const Text("5倍速"))
],
),
// 视频的进度条
VideoProgressIndicator(_controller, allowScrubbing: true),
],
),
)
: Container(),
)
chewie
video_player
虽然是官方提供的插件,但是很明显它只适合拿来简单的播放视频,就比如前端的video
标签功能也很少。在这里推荐一下chewie
简介
chewie
是基于video_player
实现的,它额外提供了很多功能,比如:倍速、进度条、全屏以及其他的功能
官方文档
https://pub-web.flutter-io.cn/packages/chewie
安装
flutter pub add chewie
默认的弹出菜单是这样的
可以通过设置optionsBuilder
来进行自定义显示
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title});
final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
// 控制器
late VideoPlayerController _controller;
late ChewieController _chewieController;
late PersistentBottomSheetController<dynamic> _bottomSheetController;
// 初始化
@override
void initState() {
super.initState();
// 加载网络视频
_controller = VideoPlayerController.networkUrl(Uri.parse(
'https://www.tujuyun.com/pixabay/video/VideoBig/1024927/4006.mp4'))
..initialize().then((_) {
setState(() {});
_chewieController = ChewieController(
videoPlayerController: _controller,
autoPlay: true,
looping: true,
optionsBuilder: (context, defaultOptions) async {
// 这里面现在是只有一个设置倍速的,我们把它拿出来
// for (int i = 0; i < defaultOptions.length; i++) {
// print("默认选项:${defaultOptions[i]}");
// }
// await showDialog<void>(
// context: context,
// builder: (ctx) {
// // return AlertDialog(
// // content: ListView.builder(
// // itemCount: defaultOptions.length,
// // itemBuilder: (_, i) => ActionChip(
// // label: Text(defaultOptions[i].title),
// // onPressed: () => defaultOptions[i].onTap!(),
// // ),
// // ),
// // );
// },
// );
_bottomSheetController =
Scaffold.of(context).showBottomSheet((BuildContext context) {
return SizedBox(
height: 200,
child: ListView(
children: <Widget>[
ListTile(
leading: const Icon(Icons.speed),
title: const Text('倍速'),
onTap: () => defaultOptions[0].onTap!(),
),
const Divider(
color: Colors.grey,
thickness: 1.0,
),
ListTile(
leading: const Icon(Icons.download),
title: const Text('下载'),
onTap: () => print("下载中.."),
),
const Divider(
color: Colors.grey,
thickness: 1.0,
),
ListTile(
leading: const Icon(Icons.close),
title: const Text('关闭'),
onTap: () => _bottomSheetController.close(),
),
],
),
);
});
},
);
});
}
@override
void dispose() {
super.dispose();
_controller.dispose();
_chewieController.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: _controller.value.isInitialized // 判断是否已经加载完成
? AspectRatio(
// 设置视频播放的宽高比
aspectRatio: _controller.value.aspectRatio,
child: Chewie(
controller: _chewieController,
),
)
: Container(),
),
);
}
}
注: chewie
还有很多其他高级功能,比如自定义UI界面、设置弹幕等。需要好好看一下官方文档,才能实现高级功能,不过上面那个例子已经可以满足基本的使用了。
image_picker
简介
用于从相册中挑选图片、视频、使用相机拍摄照片。
官方文档
https://pub-web.flutter-io.cn/packages/image_picker
安装
flutter pub add image_picker
示例:读取单张图片
class _MyHomePageState extends State<MyHomePage> {
// 图片文件
File? _image;
// 错误信息
String _error = '';
// 图片选择函数
Future<void> _pickImage() async {
// 从相册中选择图片
try {
final pickedImage =
await ImagePicker().pickImage(source: ImageSource.gallery);
if (pickedImage != null) {
setState(() {
_image = File(pickedImage.path);
});
}
} catch (e) {
setState(() {
_error = e.toString();
});
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// 图片存在则显示
if (_image != null)
Image.file(
_image!,
width: 200,
height: 200,
),
// 如果错误信息存在
if (_error.isNotEmpty) Text("错误:$_error"),
const SizedBox(
height: 20,
),
ElevatedButton(onPressed: _pickImage, child: const Text("从相册里选取图片"))
],
),
),
);
}
}
看了一下好像不能设置选择的图片格式,只能设置大小、质量
如果设置为ImagePicker().pickImage(source: ImageSource.camera)
,这是调用摄像头来进行获取图片
示例:读取多张图片
class _MyHomePageState extends State<MyHomePage> {
// 图片文件列表
final List<File> _pickedFileList = [];
// 错误信息
String _error = '';
// 图片选择函数
Future<void> _pickImage() async {
// 从相册中选择图片
try {
final pickedImageList = await ImagePicker().pickMultiImage();
if (pickedImageList.isNotEmpty) {
for (XFile image in pickedImageList) {
_pickedFileList.add(File(image.path));
}
setState(() {});
}
} catch (e) {
setState(() {
_error = e.toString();
});
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(
child: ListView.builder(
itemCount: _pickedFileList.length,
itemBuilder: (context, index) {
return Image.file(
_pickedFileList[index],
width: 200,
height: 200,
);
})),
// 如果错误信息存在
if (_error.isNotEmpty) Text("错误:$_error"),
const SizedBox(
height: 20,
),
ElevatedButton(onPressed: _pickImage, child: const Text("从相册里选取图片"))
],
),
),
);
}
}
要长按图片,才能够一次选择多个,最后在点击右上角的选择。轻触会直接选中图片。另外看了下pickMultiImage
里的入参好像不支持限制图片的个数
示例:选择单个视频
选择视频稍微复杂一点,还需要借助video_player
等插件才能更进行预览。
class _MyHomePageState extends State<MyHomePage> {
// 错误信息
String _error = '';
// 视频信息
late File _video;
// 视频播放器
VideoPlayerController? _videoPlayerController;
Future<void>? _videoPlayerInitializer;
// 选择视频
Future<void> _pickVideo() async {
// 从相册中选择视频
try {
final pickedVideo =
await ImagePicker().pickVideo(source: ImageSource.gallery);
if (pickedVideo != null) {
setState(() {
_video = File(pickedVideo.path);
_videoPlayerController = VideoPlayerController.file(_video);
_videoPlayerInitializer = _videoPlayerController!.initialize();
// 播放视频
_videoPlayerController!.play();
});
}
} catch (e) {
setState(() {
_error = e.toString();
});
}
}
void dispose() {
_videoPlayerController?.dispose();
super.dispose();
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (_videoPlayerController != null)
FutureBuilder(
future: _videoPlayerInitializer,
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return SizedBox(
width: 300,
height: 200,
child: AspectRatio(
aspectRatio:1.5,
child: VideoPlayer(_videoPlayerController!),
),
);
} else {
return const CircularProgressIndicator();
}
},
),
// 如果错误信息存在
if (_error.isNotEmpty) Text("错误:$_error"),
const SizedBox(
height: 20,
),
ElevatedButton(onPressed: _pickVideo, child: const Text("从相册里选取视频"))
],
),
),
);
}
}
file_picker
简介
一个包,允许您使用本机文件资源管理器来选择单个或多个文件,具有扩展筛选支持。
官方文档
https://pub-web.flutter-io.cn/packages/file_picker
安装
flutter pub add file_picker
示例:选择单个文件
class _MyHomePageState extends State<MyHomePage> {
// 错误信息
String _error = '';
// 文件路径
String _filePath = '';
// 选择文件
Future _pickFile() async {
try {
FilePickerResult? result = await FilePicker.platform.pickFiles(
dialogTitle: "选择图片",
type: FileType.image, // 设置文件的类型
);
if (result != null) {
setState(() {
_filePath = result.files.single.path!;
});
}
} catch (e) {
setState(() {
_error = e.toString();
});
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
// File 是 io包下的
_filePath == '' ? const Text("未选择文件") : Image.file(File(_filePath)),
// 如果错误信息存在
if (_error.isNotEmpty) Text("错误:$_error"),
const SizedBox(
height: 20,
),
ElevatedButton(onPressed: _pickFile, child: const Text("选择一个图片"))
],
),
),
);
}
}
示例:选择多个文件
FilePickerResult? result = await FilePicker.platform.pickFiles(allowMultiple: true);
if (result != null) {
List<File> files = result.paths.map((path) => File(path)).toList();
} else {
// User canceled the picker
}
其他功能略,可以自行查看官方文档