Flutter:文件读取—— video_player、chewie、image_picker、file_picker

前言

简单学习一下几个比较好用的文件读取库

video_player

简介

用于视频播放

官方文档
https://pub-web.flutter-io.cn/packages/video_player

安装

javascript 复制代码
flutter pub add video_player

加载网络视频

javascript 复制代码
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,
        ),
      ),
    );
  }
}


加载本地视频

javascript 复制代码
   _controller = VideoPlayerController.asset('lib/assets/video/3998.mp4')
      ..initialize().then((_) {
        setState(() {});
      });

设置倍速和进度条

javascript 复制代码
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

安装

javascript 复制代码
flutter pub add chewie

默认的弹出菜单是这样的

可以通过设置optionsBuilder来进行自定义显示

javascript 复制代码
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

安装

dart 复制代码
flutter pub add image_picker

示例:读取单张图片

dart 复制代码
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();
      });
    }
  }

  @override
  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) ,这是调用摄像头来进行获取图片

示例:读取多张图片

dart 复制代码
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();
      });
    }
  }

  @override
  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等插件才能更进行预览。

dart 复制代码
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();
      });
    }
  }

  @override
  void dispose() {
    _videoPlayerController?.dispose();
    super.dispose();
  }

  @override
  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

安装

dart 复制代码
flutter pub add file_picker

示例:选择单个文件

dart 复制代码
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();
      });
    }
  }

  @override
  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("选择一个图片"))
          ],
        ),
      ),
    );
  }
}

示例:选择多个文件

dart 复制代码
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
}

其他功能略,可以自行查看官方文档

相关推荐
problc10 小时前
Flutter中文字体设置指南:打造个性化的应用体验
android·javascript·flutter
lqj_本人18 小时前
鸿蒙next选择 Flutter 开发跨平台应用的原因
flutter·华为·harmonyos
lqj_本人1 天前
Flutter&鸿蒙next 状态管理框架对比分析
flutter·华为·harmonyos
起司锅仔1 天前
Flutter启动流程(2)
flutter
hello world smile1 天前
最全的Flutter中pubspec.yaml及其yaml 语法的使用说明
android·前端·javascript·flutter·dart·yaml·pubspec.yaml
lqj_本人1 天前
Flutter 的 Widget 概述与常用 Widgets 与鸿蒙 Next 的对比
flutter·harmonyos
iFlyCai1 天前
极简实现酷炫动效:Flutter隐式动画指南第二篇之一些酷炫的隐式动画效果
flutter
lqj_本人1 天前
Flutter&鸿蒙next 中使用 MobX 进行状态管理
flutter·华为·harmonyos
lqj_本人1 天前
Flutter&鸿蒙next 中的 setState 使用场景与最佳实践
flutter·华为·harmonyos