我想在Flutter中使用Dio和multi_image_picker插件上传多张图片。
List<Asset>
就是问题所在,因为我无法从List<Asset>
转换为List<File>
,所以如果您有任何解决方案可以帮助我。
尝试使用:
multi_image_picker: ^4.6.1
dio: ^3.0.4
谢谢
Bona SR。
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:merchantside/helper/colorhelper.dart';
import 'package:merchantside/merchantside/login.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';
class ListImages extends StatefulWidget {
String errorMessage = "";
@override
_ListImagesState createState() => new _ListImagesState();
}
class _ListImagesState extends State<ListImages> {
List<Asset> images = List<Asset>();
List<File> listImages = [];
@override
void initState() {
super.initState();
}
Widget buildGridView() {
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
}
void _uploadFiles() async {
String uid = await FlutterSecureStorage().read(key: "getTocken");
try {
var dio = Dio();
FormData formData = new FormData.fromMap({
"pictures[]": images,
});
Response resp = await dio.post(
mainUrl + 'merchant/upload-galleries',
data: formData,
onSendProgress: (int sent, int total) {
//
},
options: Options(
headers: {
HttpHeaders.authorizationHeader: uid,
},
)
);
if(resp.statusCode == 200) {
print("============= Print Resp data: ");
print(resp.data);
}
} catch (e) {
print(e);
}
}
Future<void> loadAssets() async {
List<Asset> resultList = List<Asset>();
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 6,
enableCamera: true,
selectedAssets: images,
cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
materialOptions: MaterialOptions(
actionBarColor: "#abcdef",
actionBarTitle: "Example App",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
print(e);
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if (!mounted) return;
setState(() {
images = resultList;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton(
heroTag: "btn1",
backgroundColor: ColorHelper.orange,
child: Icon(Icons.add_photo_alternate),
onPressed: loadAssets,
),
appBar: new AppBar(
title: Text('បញ្ជីរូបភាព'),
backgroundColor: ColorHelper.orange,
),
body: Column(
children: <Widget>[
//Error message
errorMessage != "" ?
Container(
margin: EdgeInsets.only(left: 10, right: 10, top: 10),
height: 50,
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(4)),
color: ColorHelper.red.withOpacity(0.5),
),
child: Center(
child: Text("$errorMessage", style: TextStyle(color: ColorHelper.swhite, fontSize: 15),),
),
):
Container(),
Expanded(
child: Container(
margin: EdgeInsets.only(left: 10, right: 10, top: 10),
child: buildGridView(),
),
),
SafeArea(
child: Container(
margin: EdgeInsets.all(10),
decoration: BoxDecoration(
color: ColorHelper.green,
borderRadius: BorderRadius.all(Radius.circular(4))
),
height: 50,
child: InkWell(
onTap: () {
if(images.length > 0) {
setState(() {
errorMessage = "";
});
// Call function upload multiple files
_uploadFiles();
} else {
setState(() {
errorMessage = "សូមបញ្ជូលរូបភាព";
});
}
},
child: Center(
child: Text("រួចរាល់", style: TextStyle(color: ColorHelper.swhite, fontSize: 15, fontWeight: FontWeight.w500,),),
),
),
),
),
],
),
);
}
}
答案 0 :(得分:1)
当您从图库中选取图像时,称为getFileList()然后称为设置状态,请首先使用文件列表的全局变量,并在每次再次选择图像时清除此列表。
List<File> listFile = List<File>();
images = resultList;
_error = error;
getFileList();
void getFileList() async{
listFile.clear();
for(int i=0; i<images.length; i++){
var path= await images[i].filePath;
print(path);
var file=await getImageFileFromAssets(path);
print(file);
listFile.add(file);
}
setState(() {
});
}
getImageFileFromAsset用于将资产转换为文件
Future<File> getImageFileFromAsset(String path) async {
final file = File(path);
return file;
}
并在formdata中使用listFile。
答案 1 :(得分:1)
以下是从Asset
列表中获取字节数组列表的方法:
List<Asset> images;
...
List<ByteData> byteDataList = await Future.wait(images.map((Asset image) => image.getByteData()));
List<Uint8List> byteArrayList = byteDataList.map((ByteData byteData) {
ByteBuffer byteBuffer = byteData.buffer;
return byteBuffer.asUint8List(byteData.offsetInBytes, byteBuffer.lengthInBytes);
}).toList();
现在,您可以使用字节数组列表使用所选的网络客户端来构建有效负载。对于不使用第三方网络客户端的用户,这将是一个MultipartRequest
,其中有多个MultipartFile.fromBytes
。
答案 2 :(得分:1)
您无需将资产转换为文件,您可以将其作为字节数组发送。
只需创建每个图像的Multipart对象。
您可以从资产中获取字节数组
ByteData byteData = await asset.getByteData();
List<int> imageData = byteData.buffer.asUint8List();
然后它可以通过 MultipartFile.fromBytes()方法。
所以看起来像
String url = "upload/url";
List<Asset> images = List<Asset>();
List<MultipartFile> multipartImageList = new List<MultipartFile>();
if (null != images) {
for (Asset asset in images) {
ByteData byteData = await asset.getByteData();
List<int> imageData = byteData.buffer.asUint8List();
MultipartFile multipartFile = new MultipartFile.fromBytes(
imageData,
filename: 'load_image',
contentType: MediaType("image", "jpg"),
);
multipartImageList.add(multipartFile);
}
FormData formData = FormData.fromMap({
"multipartFiles": multipartImageList,
"userId": '1'
});
Dio dio = new Dio();
var response = await dio.post(url, data: formData);
}
答案 3 :(得分:0)
您可以使用file_picker并获取直接选择的文件列表。它支持多选并提供文件路径作为响应。这将是最简单的方法。
List<File> files = await FilePicker.getMultiFilePath(
type: FileType.IMAGE);
答案 4 :(得分:0)
我在我的应用程序中使用了dio和multi_image插件,它可以正常工作。在做什么是在这里给我代码片段。您可以说这是工作版本,应该可以在任何应用中使用。
bloc班
{
"name": "ABC",
"address":[
{
"type": "primary",
"city": "XYZ",
"state": "PQR",
"reachingAddress":[
{
"modeOfTravel": "AIR",
"description": "blah blah"
},
{
"modeOfTravel": "TRAIN",
"description": "blah blah blah"
}
]
},
{
"type": "secondary",
"city": "XYZ1",
"state": "PQR1",
"reachingAddress":[
{
"modeOfTravel": "AIR",
"description": "blah1 blah1"
},
{
"modeOfTravel": "TRAIN",
"description": "blah1 blah1 blah1"
}
]
}
]
}
//在启动api调用时调用此方法
ABC primary XYZ PQR AIR blah blah
ABC primary XYZ PQR TRAIN blah blah blah
ABC secondary XYZ1 PQR1 AIR blah1 blah1
ABC secondary XYZ1 PQR1 TRAIN blah1 blah1 blah1
因此,您已经获得了图像列表。并将这些列表设置到您的请求模型类中。现在,使用dio将这些图像作为多部分发送。
API类方法
//从存储库类调用
final imageController = BehaviorSubject<List<Asset>>();
StreamSink<List<Asset>> get sinkImages =>
imageController.sink;
Stream<List<Asset>> get getImages => imageController.stream;
Future<void> loadImages(imageCount) async {
List<Asset> imageList = List<Asset>();
String error = 'No Error Dectected';
try {
imageList = await MultiImagePicker.pickImages(
maxImages: imageCount,
enableCamera: true,
cupertinoOptions: CupertinoOptions(
takePhotoIcon: "chat",
),
materialOptions: MaterialOptions(
actionBarColor: "#0A73B1",
statusBarColor: "#0A73B1",
actionBarTitle: "Select Image",
allViewTitle: "All Photos",
useDetailsView: false,
selectCircleStrokeColor: "#000000",
),
);
} on Exception catch (e) {
error = e.toString();
print(error);
}
_error = error;
imageController.add(imageList);
}
//上传图片API请求
Future<GenericResponse> uploadImageRequest() async {
RequestModel reqModel = RequestModel(
uploadImageList: getImages);
final SharedPref prefs = SharedPref();
String token = await prefs.readString(accessToken);
GenericResponse response = await _application.repository
.uploadRequest(reqModel: reqModel, accessToken: token);
return response;
}
// podo模型类
Future<GenericResponse> uploadRequest(
{RequestModel reqModel, String accessToken}) async {
return await _apiProvider.uploadRequest(
reqModel: reqModel, accessToken: accessToken);
}
答案 5 :(得分:0)
简单有效:
Map<String, dynamic> params = Map();
params['images'] = null;
Map<String, dynamic> headers = {
HttpHeaders.contentTypeHeader: 'multipart/form-data',
};
List<MultipartFile> multipart = List<MultipartFile>();
//listImage is your list assets.
for (int i = 0; i < listImage.length; i++) {
ByteData byteData = await listImage[i].getByteData();
List<int> imageData = byteData.buffer.asUint8List();
print("name: ${listImage[i].name}");
String fileName = "${listImage[i].name}";
multipart.add(MultipartFile.fromBytes(imageData, filename: fileName, contentType: MediaType("image", "jpg"),));
}
if (multipart.isNotEmpty){
params['images'] = multipart;
}
FormData formData = new FormData.fromMap(params);
答案 6 :(得分:0)
FormData formData = FormData.fromMap({
'id': 'ZE8980',
'name': 'myTitle',
'age':'22',
'order_images': [
for (var file in images)
// ....SPRED images
...{
await MultipartFile.fromFile(getImage(file).imageFile.path,
filename: getImage(file).imageFile.path.split('/').last)
}.toList()
]
});
Dio dio = new Dio();
var response = await dio.post(url, data: formData);