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

news2024/12/23 9:32:28

前言

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

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
}

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/850499.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

uniapp 将标题背景更换背景图片 完美解决(附加源码+实现效果图)

问题描述 今天拿到小程序的设计效果图后&#xff0c;标题部分背景需要加背景图片&#xff0c;以往我做的都是标题背景更换颜色等&#xff0c;加背景图片还是第一次遇到&#xff0c;大家可以先看下我的效果图是否与你遇到的问题一致&#xff01; 首页标题的背景是个背景图片。 …

MachineLearningWu_13/P60-P64_Tensorflow

P60-P64的学习目录如下&#xff0c; x.1 TF网络模型实现 以一个简单的TF的分类网络为例&#xff0c;将模型翻译成框架下的语义&#xff0c;即如右侧所表达的。 当然上面对于分类网络的解释是一个简洁的解释&#xff0c;我们来进行更加具象的了解一下。左边是机器学习的三步骤&…

RS485实验

RS485实验 介绍 RS485采用差分信号进行传输&#xff0c;半双工通信。RS485是一个总线&#xff0c;在同一总线上最多可以挂接32个节点。通信流程简单理解为默认为接收状态&#xff0c;发送数据时切换为发送状态&#xff0c;数据发送完毕后切换为接收状态。发送和接收分别由一个…

01_什么是ansible、基本架构、ansible工作机制、Ansible安装、配置主机清单、设置SSH无密码登录等

1.什么是ansible 1.1.基本介绍 1.2.基本架构 1.3.基本特征 1.4.优点 1.5.ansible工作机制 2.Ansible安装 2.1.机器准备 2.2.安装ansible 2.2.1.安装epel源 2.2.2.安装ansible 2.2.3.查看ansible版本 2.2.4.树状结构展示文件夹 2.2.4.1.其中ansible.cfg的内容如下 2.2.4.2.host的…

SQL 相关子查询 和 不相关子查询、Exists 、Not Exists、 多表连接(包含自连接)

不相关子查询 子查询的查询条件不依赖于父查询&#xff0c;称不相关子查询。子查询可以单独运行的 select stu_id,sex,age from student t where sex(select sexfrom studentwhere stu_id10023 )相关子查询 关联子查询 子查询的查询条件依赖于父查询&#xff0c;称为 相关子…

C++笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究

C笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究 code review! 文章目录 C笔记之两个类的实例之间传递参数——通过构造函数传递类对象的方法详细探究1.传递对象的const引用——ClassB的实例只能访问ClassA的实例&#xff0c;但不会修改ClassA的实…

Python小白学习:超级详细的字典介绍(字典的定义、存储、修改、遍历元素和嵌套)

目录 一、字典简介1.1 创建字典1.2 访问字典中的值1.3 添加键值对1.4 修改字典中的值实例 1.5 删除键值对1.6 由多个类似对象组成的字典1.7 使用get()访问值1.8 练习题 二、遍历字典2.1 遍历所有键值对实例 2.2 遍历字典中的所有键2.3 按照特定顺序遍历字典中的所有键2.4 遍历字…

10_Pulsar跨机房复制、Pulsar跨机房复制

2.2.4.Pulsar跨机房复制 2.2.5.Pulsar跨机房复制 如何配置 2.2.4.Pulsar跨机房复制 在大型的分布式系统中&#xff0c;都会涉及到跨多个数据中心的需求&#xff0c;通常会使用跨地域复制机制提供额外的冗余防止服务无法正常运作。Apache Pulsar 的跨地域多机房互备特性&#…

Android 13 Hotseat定制化修改——001 hotseat布局方向

目录 一.背景 二.hotseat布局方向 一.背景 由于需求是需要自定义修改Hotseat,所以此篇文章是记录如何自定义修改hotseat的,应该可以覆盖大部分场景,修改点有修改hotseat布局方向,hotseat图标数量,hotseat图标大小,hotseat布局位置,hotseat图标禁止形成文件夹,hotseat图…

接口测试——python接口开发(二)

目录 1. python接口开发框架Flask简介与安装 2. 使用Flask开发一个Get接口 3. 使用Flask开发一个Post接口 4. Flask结合PyMySQL接口与数据库的交互 1. python接口开发框架Flask简介与安装 Flask接口测试框架的简介与安装Flask是轻量级的web开发框架相比于其他框架&#xff…

Could not resolve host: mirrorlist.centos.org; Unknown error解决方法

今天服务器安装完CentOS系统后&#xff0c;安装网络的时候&#xff0c;出现无法联网yum yum -y install net-tools 以上代码无法运行并报错&#xff0c;这里我要提醒大家&#xff0c;如果在初始安装的时候选中安装网络工具模块就不用在安装net-tools了&#xff0c;因为我选中…

CycleGAN论文解读及代码实现

paper: https://arxiv.org/pdf/1703.10593.pdf github: https://github.com/aitorzip/PyTorch-CycleGAN 1 cycleGAN 小结 网络&#xff1a; 生成器2个&#xff1a;G_A&#xff0c;G_B 判别器两个&#xff1a; D_A&#xff0c;D_B损失函数8个 6个生成器损失函数 2个判别器损失…

Freemarker:生成HTML文本文件

前置工作参考&#xff1a; Freemarker&#xff1a;基本使用_moreCalm的博客-CSDN博客 1、修改application.yml配置文件 server:port: 8881 #服务端口 spring:application:name: freemarker-demo #指定服务名freemarker:cache: false #关闭模板缓存&#xff0c;方便测试settin…

leetcode904. 水果成篮(java)

水果成篮 leetcode904. 水果成篮题目描述滑动窗口代码演示 回溯算法 leetcode904. 水果成篮 难度 - 中等 leetcode 904 水果成蓝 题目描述 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树…

PPG心率血氧检测健康型沙发方案

《中国心血管健康与疾病报告2021》数据显示&#xff0c;我国心血管病患病人数已达 3.3 亿。目前&#xff0c;心脑血管病 死亡占城乡居民总死亡原因的首位&#xff0c;农村为46.7%&#xff0c;城市为44%。老年人是心脑血管病的主要发病体&#xff0c;老年 人患心脑血管病的几率较…

jmeter测试rpc接口-使用dubbo框架调用【杭州多测师_王sir】

1.基于SOAP架构。基于XML规范。基于WebService协议。特点:接口地址?wsdl结尾2.基于RPC架构&#xff0c;基于dubbo协议&#xff0c;thrift协议。SpringCloud微服务。3.基于RestFul架构&#xff0c;基于json规范。基于http协议(我们常用的都是这种&#xff0c;cms平台也是) Rest…

【数据分享】2000-2022年我国乡镇人口数量数据(免费获取/Shp/Excel格式)

在之前的文章中我们分享了基于LandScan数据集的2000-2022年的1km精度的全球、全国、分省、分市的人口空间分布栅格数据&#xff08;可查看之前的文章获悉详情&#xff09;。以及基于栅格数据处理出的Shp和Excel两种格式的我国省市县三级的2000-2022年度的人口数量数据&#xff…

【密码学】六、公钥密码

公钥密码 1、概述1.1设计要求1.2单向函数和单向陷门函数 2、RSA公钥密码体制2.1加解密2.2安全性分析 3、ElGamal公钥密码体制3.1加解密算法3.2安全性分析 4、椭圆曲线4.1椭圆曲线上的运算4.2ECC 5、SM2公钥密码体制5.1参数选取5.2密钥派生函数5.3加解密过程5.3.1初始化5.3.2加密…

photoshop生成器引入到electron项目(electron与photoshop建立通信)

Photoshop引入了nodejs&#xff0c;在启动的时候&#xff0c;通过pipe调起nodejs运行时核心generator-builtin&#xff0c;通过KLVR机制与ps进行通信和交互&#xff0c;同时会加载用户编写的扩展。 这里记录一下引入时的踩坑过程 generator-core就是它的源码&#xff0c;elect…

【项目部署】JavaScript解析JSON解析报错Unexpected token xxx is not valid JSON

问题背景 这个报错发生在之前部署的一个前后端分离的项目中。后端使用的Spring Boot&#xff0c;前端使用的JavaScript&#xff0c;前后端交互使用Thymeleaf框架。 现象 项目组的另一个小伙伴说&#xff0c;突然有个页面打不开了&#xff0c;整个页面全空白。我F12打开浏览器…