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

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:other SelectFileData({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 createState return _SelectImageVideo(); } } class _SelectImageVideo extends State<SelectImageVideo> { List<SelectFileData> _selectFileList = []; List<File> _backFileList = []; VideoPlayerController _videoPlayerController; Widget build(BuildContext context) { // TODO: implement build return 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,不是ClipRect borderRadius: 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(
上一篇:用python,将有道词典中的生词导入扇贝单词


下一篇:Leetcode-894-所有可能的真二叉树-c++