引入库 wechat_assets_picker: ^6.0.5
、video_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;}));}