【flutter封装图片/视频选择控件】

在这里插入图片描述在这里插入图片描述
引入库 wechat_assets_picker: ^6.0.5video_player: ^2.5.1 # 视频播放 flutter_screenutil: ^5.7.0

import 'dart:async';
import 'dart:io';
import 'package:generated/l10n.dart';
import 'package:jade/configs/PathConfig.dart';
import 'package:jade/customWidget/addImageVideoBtn.dart';
import 'package:jade/utils/DialogUtils.dart';
import 'package:jade/utils/JadeColors.dart';
import 'package:jade/utils/Utils.dart';
import 'package:util/easy_loading_util.dart';
import 'package:util/permission_util.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:video_player/video_player.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';class SelectFileData {File file;int type; // 1:image  2:video 3:audio  default:otherSelectFileData({this.file, this.type});
}/*
* 图片/视频选择
* 只能选择一条视频,选择多条视频未完善所以存在选多条视频时每条视频都相同的bug
* */
class SelectImageVideo extends StatefulWidget {String title;String desc;String postscript;int maxLength; //最大选择数量RequestType requestType;bool discrete; //是否分离单独选择(只能选图片或视频)bool showExample; //是否显示查看示例按钮Color bgColor; //按钮背景颜色Function selectBack;SelectImageVideo({this.title, this.desc,this.postscript, this.maxLength, this.requestType, this.discrete = false,this.showExample = false, this.bgColor,this.selectBack});State<StatefulWidget> createState() {// TODO: implement createStatereturn _SelectImageVideo();}
}class _SelectImageVideo extends State<SelectImageVideo> {List<SelectFileData> _selectFileList = [];List<File> _backFileList = [];VideoPlayerController _videoPlayerController;Widget build(BuildContext context) {// TODO: implement buildreturn Column(crossAxisAlignment: CrossAxisAlignment.start,children: [Text.rich(TextSpan(children: [TextSpan(text: widget.title,style: TextStyle(color: JadeColors.grey_2, fontSize: 30.sp, fontWeight: FontWeight.w600)),if(widget.postscript != null)TextSpan(text: widget.postscript,style: TextStyle(color: JadeColors.grey, fontSize: 24.sp, fontWeight: FontWeight.w600)),])),if (widget.desc != null)Container(margin: EdgeInsets.only(top: 10.w),child: Text(widget.desc, style: TextStyle(color: JadeColors.grey, fontSize: 24.sp))),SizedBox(height: 30.w),Row(mainAxisAlignment: MainAxisAlignment.start,children: [if (widget.showExample)GestureDetector(child: Container(margin: EdgeInsets.only(right: 20.w),child: Stack(alignment: Alignment.center,children: [ClipRRect(borderRadius: BorderRadius.circular(8),child: Image.asset(PathConfig.imageExperienceExample,fit: BoxFit.fill, width: 220.w, height: 220.w),),Container(width: 220.w,height: 220.w,decoration: BoxDecoration(color: Colors.black45, borderRadius: BorderRadius.circular(8)),),Text('点击查看示例', style: TextStyle(color: Colors.white, fontSize: 28.sp))],)),onTap: () {Utils().hideKeyboard(context);DialogUtils().experienceStationRealisticImagesDialog(title: '实景图示例',desc: '需拍摄清晰格口照片,并参照线上体验秀格口序号,在图片对应位置标注对应序号。',imageUrl: PathConfig.httpExperienceRealisticImages);},),Expanded(child: SizedBox(height: 220.w,child: ListView.separated(scrollDirection: Axis.horizontal,itemBuilder: (context, index) {if (_selectFileList.length < widget.maxLength && index == _selectFileList.length) {return GestureDetector(child: addImageVideoBtn(widget.requestType == RequestType.video? '添加视频': widget.requestType == RequestType.image? '添加图片': widget.requestType == RequestType.common? '添加图片/视频': '添加图片/视频/音频',widget.bgColor ?? JadeColors.grey_5),onTap: () async {Utils().hideKeyboard(context);bool _isAuth = await PermissionUtil.isAuthStorage();if (!_isAuth) {WidgetsBinding.instance.addPostFrameCallback((_) {DialogUtils().showGeneralDialogFunction(context, '存储权限', '用于上传照片、视频等场景', notClose: true);Future.delayed(Duration(seconds: 5), () {Navigator.of(context).pop();});});}if(widget.discrete){_openImageOrVideoSelect(index);}else{_callSelectImageVideo(index);}_backFileCall();});}return Stack(alignment: Alignment.topRight,children: [Container(height: 220.w,width: 220.w,decoration: BoxDecoration(borderRadius: BorderRadius.circular(8)),child: ClipRRect(//是ClipRRect,不是ClipRectborderRadius: BorderRadius.circular(8),child: _selectFileList[index].type == 2? Stack(alignment: Alignment.center,children: [VideoPlayer(_videoPlayerController),Container(width: 60.w,height: 60.w,child: Image.asset('images/video/icon_pause.png',fit: BoxFit.fill,))],): Image.file(_selectFileList[index].file,width: 220.w,height: 220.w,cacheWidth: 100,cacheHeight: 100,fit: BoxFit.fill,frameBuilder: (context, child, frame, wasSynchronouslyLoaded) {if (wasSynchronouslyLoaded) {return child;}return AnimatedOpacity(child: child,opacity: frame == null ? 0 : 1,duration: const Duration(seconds: 1),curve: Curves.easeOut,);}))),GestureDetector(child: Container(padding: EdgeInsets.all(5),child: Image.asset(PathConfig.iconDeleteImageWhite, width: 34.w, height: 34.w)),onTap: () {if(_selectFileList[index].type == 2){_videoPlayerController = null;}_selectFileList.removeAt(index);_backFileCall();})],);},shrinkWrap: true,separatorBuilder: (context, index) => Container(width: 20.w),itemCount:_selectFileList.length < widget.maxLength ? _selectFileList.length + 1 : _selectFileList.length),))],)],);}//判断是否已经选择了视频bool _selectedVideo(){for (var selectFile in _selectFileList) {if(selectFile.type == 2){return true;}}return false;}//选择弹窗_openImageOrVideoSelect(int index) async {int value = await showCupertinoModalPopup<int>(builder: (BuildContext context) => CupertinoActionSheet(actions: <Widget>[CupertinoActionSheetAction(child: Text(S.current.p12),onPressed: (){widget.requestType = RequestType.image;_callSelectImageVideo(index);Navigator.pop(context, 1);},),CupertinoActionSheetAction(child: Text(S.current.p13),onPressed: (){if(_selectedVideo()){esLoadingToast('已选择一条视频');Navigator.pop(context, 2);return;}widget.requestType = RequestType.video;_callSelectImageVideo(index);Navigator.pop(context, 2);},),],cancelButton: CupertinoActionSheetAction(child: Text(S.current.quxiao),onPressed: () => Navigator.pop(context, 3),), // 取消按钮),context: context,);}//调用图片选择器_callSelectImageVideo(int index) async {List<SelectFileData> _resultFileList = await selectImages(requestType: widget.requestType);if (_resultFileList.isNotEmpty) {setState(() {_selectFileList.addAll(_resultFileList);});if (_selectFileList[index].type == 2) {VideoPlayerController _dvideoPlayerController = VideoPlayerController.file(_selectFileList[index].file);_dvideoPlayerController.initialize().then((_) {Duration duration = _videoPlayerController.value.duration;int videoTime = (duration.inMinutes * 60) + duration.inSeconds;if (videoTime > 60) {esLoadingToast('发布视频长度不能大于1分钟');_dvideoPlayerController = null;_videoPlayerController = null;setState(() {_selectFileList.removeAt(index);});}});_videoPlayerController = _dvideoPlayerController;}}}_backFileCall() {_backFileList.clear();if (widget.selectBack != null) {_selectFileList.forEach((element) {_backFileList.add(element.file);});widget.selectBack(_backFileList);}setState(() {});}//图片选择器Future<List<SelectFileData>> selectImages({RequestType requestType}) async {Completer<List<SelectFileData>> _completer = Completer<List<SelectFileData>>();List<SelectFileData> _imageFiles = [];try {List<AssetEntity> images = await AssetPicker.pickAssets(context,maxAssets: requestType == RequestType.video ? 1 : widget.maxLength - _selectFileList.length, requestType: requestType ?? RequestType.image);if (images != null && images.length > 0) {for (int i = 0; i < images.length; i++) {var _type = images[i].typeInt;File _file = await images[i].file;SelectFileData _selectFileData = SelectFileData(file: _file, type: _type);_imageFiles.add(_selectFileData);}_completer.complete(_imageFiles);} else {_completer.complete([]);}} on Exception catch (e) {print(e);}return _completer.future;}
}

添加按钮

import 'package:jade/configs/PathConfig.dart';
import 'package:jade/utils/JadeColors.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';Widget addImageVideoBtn(String btnTitle,Color bgColor){return Container(width: 220.w,height: 220.w,padding: EdgeInsets.symmetric(horizontal: 10),decoration: BoxDecoration(color: bgColor,borderRadius: BorderRadius.circular(10)),child: Row(mainAxisAlignment: MainAxisAlignment.center,children: [Image.asset(PathConfig.iconAddGrey,width: 22.w,height: 22.w),Flexible(child: Text(btnTitle,style: TextStyle(fontSize: 24.sp,color: JadeColors.grey_18),maxLines: 2,textAlign: TextAlign.center))]),);
}

调用

 //上传反馈图片模块_feedbackSelectImage(){return Container(margin: EdgeInsets.only(top: 40.w),child: SelectImageVideo(title: '反馈',postscript: '(可上传5张图和60s视频)',maxLength: 6,requestType: RequestType.common,discrete: true,bgColor: Colors.white,selectBack: (selectedFiles){_selectFeedbackImageFiles = selectedFiles;}));}

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

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

相关文章

Linux:ip和ip协议的初步认识

文章目录 ip协议基本认识ip协议的报头网段划分ip的类型划分 ip协议基本认识 前面对于TCP的内容已经基本结束了&#xff0c;那么这也就意味着在传输层也已经结束了&#xff0c;那么下一步要进入的是的是网络层&#xff0c;网络层中也有很多种协议&#xff0c;这里主要进行解析的…

安装Qrcode库的方法最终解答!_Python第三方库

安装Python第三方库Qrcode 我的环境&#xff1a;Window10&#xff0c;Python3.7&#xff0c;Anaconda3&#xff0c;Pycharm2023.1.3 Qrcode库 Qrcode库是一个专门生成二维码的库。它能够让你很容易地创建不同大小、颜色和包含不同类型数据的二维码&#xff0c;支持生成 GIF 动…

力扣2684---矩阵中移动的最大次数(DFS,Java、中等题)

目录 题目描述&#xff1a; 思路描述&#xff1a; 代码&#xff1a; 纯递归&#xff1a; 带有记忆化搜索的递归&#xff1a; 题目描述&#xff1a; 给你一个下标从 0 开始、大小为 m x n 的矩阵 grid &#xff0c;矩阵由若干 正 整数组成。 你可以从矩阵第一列中的 任一 单…

基于ZooKeeper的Kafka分布式集群搭建与集群启动停止Shell脚本

下载Kafka压缩包 下方是Kafka官网下载地址&#xff0c;本文使用Kafka 3.0.0在虚拟机环境中搭建分布式集群。 Apache Kafka Downloads link 虽然在Kafka 2.8.0之后可以使用KRaft模式搭建高可用的集群以提高数据处理效率&#xff0c;但是目前还有许多企业依然使用ZooKeeper搭建K…

Linux驱动学习:从Linux主机nfs共享文件到uboot

第一步&#xff1a;在Linux主机上开启NFS服务&#xff0c;使用如下命令安装NFS服务&#xff1a; sudo apt-get install nfs-kernel-server rpcbind 第二步&#xff1a;创建一个文件夹用于共享&#xff0c;直接以nfs命名就行&#xff1a; 第三步&#xff1a;打开nfs服务配置文…

go库x/text缺陷报告CVE-2022-32149的处理方案

#问题描述 go库 golang.org/x/text &#xff0c;注意这里不是go的源码&#xff0c; 在0.3.8版本之前存在一个缺陷(Vulnerability) 缺陷ID CVE-2022-32149 具体描述 攻击者可以通过制作一个Accept-Language报头来导致拒绝服务。 具体的原因是&#xff0c;在解析这个Accept-L…

CSS3新增的语法(三)【2D,3D,过渡,动画】

CSS3新增的语法&#xff08;三&#xff09;【2D,3D,过渡&#xff0c;动画】 10.2D变换10.1. 2D位移10.2. 2D缩放10.3. 2D旋转10.4. 2D扭曲&#xff08;了解&#xff09;10.5. 多重变换10.6. 变换原点 11. 3D变换11.1. 开启3D空间11.2. 设置景深11.3. 透视点位置11.4. 3D 位移11…

反截屏控制技术如何防止信息通过手机拍照泄漏?

反截屏控制技术为企业数据安全提供了重要的防护措施。通过以下几点&#xff0c;有效阻止了信息通过拍照等方式的泄漏&#xff1a; 反截屏控制开启&#xff0c;用户启动截屏操作时&#xff0c;允许非涉密内容截屏操作&#xff0c;但所有涉密内容窗口会自动隐藏&#xff0c;防止涉…

Spark-Scala语言实战(11)

在之前的文章中&#xff0c;我们学习了如何在spark中使用RDD中的cartesian,subtract最终两种方法。想了解的朋友可以查看这篇文章。同时&#xff0c;希望我的文章能帮助到你&#xff0c;如果觉得我的文章写的不错&#xff0c;请留下你宝贵的点赞&#xff0c;谢谢。 Spark-Scal…

2023最新汽车网络安全报告汇总

2023最新汽车网络安全报告、安全参考架构及指南汇总&#xff0c;供大家学习参考。https://t.zsxq.com/18RkG260k 汽车信息安全法律法规及标准全景图V3.2.pdf 车载智能计算基础平台参考架构2.0.pdf 车载智能计算芯片白皮书(2023版).pdf 智能驾驶行为安全评价方法发布版.pdf 智能…

填谷式无源PFC电路

目录&#xff1a; 1、概述 2、原理 1、概述 如果不采用PFC&#xff0c;那么典型开关模式电源的功率因数约为0.6&#xff0c;因而会有相当大的奇次谐波失真(第三谐波有时和基本谐波一样大)。令功率因数小于1以及来自峰值负载的谐波减少了运行设备可用的实际功率。为运行这些低…

数据结构——二叉树(堆)

大家好我是小峰&#xff0c;今天我们开始学习二叉树。 首先我们来学习什么是树&#xff1f; 树概念及结构 树是一种 非线性 的数据结构&#xff0c;它是由 n &#xff08; n>0 &#xff09;个有限结点组成一个具有层次关系的集合。 把它叫做树是因 为它看起来像一棵倒挂的…

【2024红明谷】三道Web题目的记录

红明谷 文章目录 红明谷Web1 | SOLVED LaterWeb2 | UNSOLVEDWeb3 | SOLVED 容器已经关咯&#xff0c;所以有些场景只能靠回忆描述啦&#xff0c;学习为主&#xff0c;题目只是一个载体~ 本次比赛学习为主&#xff0c;确实再一次感受到久违的web题目的魅力了&#xff0c;可能也是…

数据转换 | Matlab基于GASF格拉姆角和场一维数据转二维图像方法

目录 效果分析基本介绍程序设计参考资料获取方式 效果分析 基本介绍 基于GASF&#xff08;Gramian Angular Summation Field&#xff09;的方法&#xff0c;将一维数据转换为二维图像的步骤描述 标准化数据&#xff1a; 首先&#xff0c;对一维时序数据进行标准化处理&#xf…

MyBatis的基本应用

源码地址 01.MyBatis环境搭建 添加MyBatis的坐标 <!--mybatis坐标--><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><!--mysql驱动坐…

『51单片机』蜂鸣器

&#x1f6a9; WRITE IN FRONT &#x1f6a9; &#x1f50e; 介绍&#xff1a;"謓泽"正在路上朝着"攻城狮"方向"前进四" &#x1f50e;&#x1f3c5; 荣誉&#xff1a;2021|2022年度博客之星物联网与嵌入式开发TOP5|TOP4、2021|2222年获评…

OpenHarmony实战:轻量级系统之配置其他子系统

除上述子系统之外&#xff0c;还有一些必要但是无需进行移植的子系统。如&#xff1a;分布式任务调度子系统、DFX子系统。 这些子系统添加方式比较简单&#xff0c;在“vendor/MyVendorCompany/MyProduct/config.json”文件中进行如下配置即可&#xff1a; {"subsystem&…

专有钉钉微应用埋点以及本地调试埋点总结

最近在对接浙政钉&#xff0c;稳定性监控、通用采集 SDK、基础埋点、基础埋点&#xff0c;每次发布上去&#xff0c;工作人员那边反馈抓取不到信息 稳定性监控代码、通用采集 SDK index.html <!-- 流量稳定监控 S 关于埋点上线打开--><script src"https://wpk-…

IDEA 中能提高开发效率的插件

目录 前言 插件 Rainbow Brackets AceJump POJO to JSON Json Helper MybatisX Maven Helper PlantUML Integration TONYYI Lingma 前言 IDEA 里又很多好用的插件可以帮助我们提升开发效率&#xff0c;这里罗列下自己开发过程中常用的插件&#xff0c;善于利用插件&…

【第十一届大唐杯全国大学生新一代信息通信技术大赛】赛题分析

赛道一 一等奖 7% 二等奖 15% 三等奖 25% 赛道二 参考文档&#xff1a; 《第十一届大唐杯全国大学生新一代信息通信技术大赛&#xff08;产教融合5G创新应用设计&#xff09;专项赛说明.pdf》 一等奖&#xff1a;7% 二等奖&#xff1a;10% 三等奖&#xff1a;20% 赛项一&am…