图片和文件选取
依赖库
主要用到两个依赖库,一个是image_picker
,一个是file_picker
file_picker
负责文件的选取,image_picker
负责图片的选取
方法封装
file_picker支持多种方法,可获取单个、多个文件的目录和文件名。
从源码中一层层往上找到获取文件的主要方法,这里看获取多文件路径的方法getMultiFilePath
,从一下的源码中可看出该方法调用了flutter自带的平台通道,从宿主机中获取指定扩展名的文件,再将文件路径通过/
分开,并存入映射中,key为文件名,value为文件路径。单个文件类似。
Future<dynamic> _getPath(
FileType fileType,
bool allowMultipleSelection,
bool allowCompression,
List<String> allowedExtensions,
Function(FilePickerStatus) onFileLoading,
) async {
final String type = describeEnum(fileType);
if (type != 'custom' && (allowedExtensions?.isNotEmpty ?? false)) {
throw Exception(
'If you are using a custom extension filter, please use the FileType.custom instead.');
}
try {
_eventSubscription?.cancel();
if (onFileLoading != null) {
_eventSubscription = _eventChannel.receiveBroadcastStream().listen(
(data) => onFileLoading((data as bool)
? FilePickerStatus.picking
: FilePickerStatus.done),
onError: (error) => throw Exception(error),
);
}
dynamic result = await _channel.invokeMethod(type, {
'allowMultipleSelection': allowMultipleSelection,
'allowedExtensions': allowedExtensions,
'allowCompression': allowCompression,
});
if (result != null && allowMultipleSelection) {
if (result is String) {
result = [result];
}
return Map<String, String>.fromIterable(result,
key: (path) => path.split('/').last, value: (path) => path);
}
return result;
} on PlatformException catch (e) {
print('[$_tag] Platform exception: $e');
rethrow;
} catch (e) {
print(
'[$_tag] Unsupported operation. Method not found. The exception thrown was: $e');
rethrow;
}
}
因此对该方法进行封装如下,获取图片文件名以做后续处理:
Future getSingleImagePath() async{
String SingleFilePath;
SingleFilePath = await FilePicker.getFilePath(type: FileType.image);
return SingleFilePath;
}
Future getMultiImagesPath() async{
Map<String,String> imagesPaths;
imagesPaths = await FilePicker.getMultiFilePath(type: FileType.image);
// Options
// List<String> allNames = filePaths.keys; // List of all file names
// List<String> allPaths = filePaths.values; // List of all paths
// String someFilePath = filePaths['fileName']; // Access a file path directly by its name (matching a key)
return imagesPaths;
}
Future getMultiFilesPath() async{
Map<String,String> filesPaths;
filesPaths = await FilePicker.getMultiFilePath(type: FileType.image);
// Options
// List<String> allNames = filesPaths.keys; // List of all file names
// List<String> allPaths = filesPaths.values; // List of all paths
// String someFilePath = filesPaths['fileName']; // Access a file path directly by its name (matching a key)
return filesPaths;
}
同时APP还要求有拍照的功能,使用另一个依赖库image_picker
,源码与file_picker
类似,不再贴出,主要使用该库的拍照功能,同样返回文件名,注意该依赖库的图片是暂存在临时目录中的:
Future getImageFileFromCamera() async{
var picker = ImagePicker();
PickedFile imageFile = await picker.getImage(source: ImageSource.camera,imageQuality: 50); //图片来源和压缩质量
if(imageFile!=null){
return File(imageFile.path).path;
}
}
使用
在项目中的调用例子:
单文件
MultipartFile photo; //将文件转换为MulitipartFile类以供使用
String displayPath; //需要在页面上显示
void _selectFile() async {
getSingleImagePath().then((path) {
MultipartFile.fromFile(path).then((value) {
photo = value;
});
setState(() {
displayPath = path.toString();
});
});
}
void _selectFilefromCamera() async {
getImageFileFromCamera().then((path) {
MultipartFile.fromFile(path).then((value) {
photo = value;
});
setState(() {
displayPath = path.toString();
});
});
}
多文件
String filesname;
String filespath;
var flag2 = 0;
List displayPath = [];
List<MultipartFile> selectedFiles = new List<MultipartFile>();
Future<void> _selectFile() async {
Map filesPaths;
getMultiFilesPath().then((value) {
filesPaths = value;
var selectedFilePaths = filesPaths.values;
MultipartFile tempfile;
for (String path in selectedFilePaths) {
displayPath.add(path);
MultipartFile.fromFile(path).then((value) {
if(value!=Null){
flag2=1;
}
tempfile = value;
selectedFiles.add(tempfile);
print(selectedFiles.length);
});
}
setState(() {
filesname = displayPath.toString();
});
});
}
Future<void> _selectFilefromCamera() async {
getImageFileFromCamera().then((value) {
displayPath.add(value);
var selectedFilePaths = value;
MultipartFile tempfile;
MultipartFile.fromFile(selectedFilePaths).then((value) {
if(value!=Null){
flag2=1;
}
tempfile = value;
selectedFiles.add(tempfile);
print(selectedFiles.length);
});
setState(() {
filesname = displayPath.toString();
});
});
}
上传
利用之前写的网络模块
var register = Map();
GlobalKey<FormState> textFromKey = new GlobalKey<FormState>();
String phoneNumber;
String password;
String password2;
String verificationCode;
MultipartFile file;
bool isShowPassWord = false;
//读取当前的Form状态
var loginForm = textFromKey.currentState;
//验证Form表单
if (loginForm.validate()) {
var register = Map();
var map = Map();
register['phoneNum'] = phoneNumber;
register['passWord'] = password;
register['verCode'] = verificationCode;
register['file'] = file;
map['register'] = register;
FormData formData = FormData.fromMap(map);
//网络部分
DioManager.getInstance().post('PatientRegister', formData,
(data){
print(data);
},
(error){
print(error);
});
}else{
ShowToast.getShowToast().showToast('请正确填写信息');
}