Image 如何选择和上传颤振中的多个图像
我试图找到如何在flutter中选择和上传多个图像,但大多数插件都不起作用,或者我不太理解它们。我发现几乎没有应用程序,但它只选择和上传一张图片。如何更改此代码,用户可以选择并上传多张图片,或者是否有其他替代方案。请详细填写,我是编码专业的大一新生。提前谢谢Image 如何选择和上传颤振中的多个图像,image,flutter,file-upload,image-uploading,Image,Flutter,File Upload,Image Uploading,我试图找到如何在flutter中选择和上传多个图像,但大多数插件都不起作用,或者我不太理解它们。我发现几乎没有应用程序,但它只选择和上传一张图片。如何更改此代码,用户可以选择并上传多张图片,或者是否有其他替代方案。请详细填写,我是编码专业的大一新生。提前谢谢 import 'package:flutter/material.dart'; import 'dart:io'; import 'package:http/http.dart' as http; import 'package:image
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:http/http.dart' as http;
import 'package:image_picker/image_picker.dart';
import 'package:mime/mime.dart';
import 'dart:convert';
import 'package:http_parser/http_parser.dart';
import 'package:toast/toast.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Image Upload Demo',
theme: ThemeData(primarySwatch: Colors.pink),
home: ImageInput());
}
}
class ImageInput extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _ImageInput();
}
}
class _ImageInput extends State<ImageInput> {
// To store the file provided by the image_picker
File _imageFile;
// To track the file uploading state
bool _isUploading = false;
String baseUrl = 'http://YOUR_IPV4_ADDRESS/flutterdemoapi/api.php';
void _getImage(BuildContext context, ImageSource source) async {
File image = await ImagePicker.pickImage(source: source);
setState(() {
_imageFile = image;
});
// Closes the bottom sheet
Navigator.pop(context);
}
Future<Map<String, dynamic>> _uploadImage(File image) async {
setState(() {
_isUploading = true;
});
// Find the mime type of the selected file by looking at the header bytes of the file
final mimeTypeData =
lookupMimeType(image.path, headerBytes: [0xFF, 0xD8]).split('/');
// Intilize the multipart request
final imageUploadRequest =
http.MultipartRequest('POST', Uri.parse(baseUrl));
// Attach the file in the request
final file = await http.MultipartFile.fromPath('image', image.path,
contentType: MediaType(mimeTypeData[0], mimeTypeData[1]));
// Explicitly pass the extension of the image with request body
// Since image_picker has some bugs due which it mixes up
// image extension with file name like this filenamejpge
// Which creates some problem at the server side to manage
// or verify the file extension
imageUploadRequest.fields['ext'] = mimeTypeData[1];
imageUploadRequest.files.add(file);
try {
final streamedResponse = await imageUploadRequest.send();
final response = await http.Response.fromStream(streamedResponse);
if (response.statusCode != 200) {
return null;
}
final Map<String, dynamic> responseData = json.decode(response.body);
_resetState();
return responseData;
} catch (e) {
print(e);
return null;
}
}
void _startUploading() async {
final Map<String, dynamic> response = await _uploadImage(_imageFile);
print(response);
// Check if any error occured
if (response == null || response.containsKey("error")) {
Toast.show("Image Upload Failed!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
} else {
Toast.show("Image Uploaded Successfully!!!", context,
duration: Toast.LENGTH_LONG, gravity: Toast.BOTTOM);
}
}
void _resetState() {
setState(() {
_isUploading = false;
_imageFile = null;
});
}
void _openImagePickerModal(BuildContext context) {
final flatButtonColor = Theme.of(context).primaryColor;
print('Image Picker Modal Called');
showModalBottomSheet(
context: context,
builder: (BuildContext context) {
return Container(
height: 150.0,
padding: EdgeInsets.all(10.0),
child: Column(
children: <Widget>[
Text(
'Pick an image',
style: TextStyle(fontWeight: FontWeight.bold),
),
SizedBox(
height: 10.0,
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Camera'),
onPressed: () {
_getImage(context, ImageSource.camera);
},
),
FlatButton(
textColor: flatButtonColor,
child: Text('Use Gallery'),
onPressed: () {
_getImage(context, ImageSource.gallery);
},
),
],
),
);
});
}
Widget _buildUploadBtn() {
Widget btnWidget = Container();
if (_isUploading) {
// File is being uploaded then show a progress indicator
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: CircularProgressIndicator());
} else if (!_isUploading && _imageFile != null) {
// If image is picked by the user then show a upload btn
btnWidget = Container(
margin: EdgeInsets.only(top: 10.0),
child: RaisedButton(
child: Text('Upload'),
onPressed: () {
_startUploading();
},
color: Colors.pinkAccent,
textColor: Colors.white,
),
);
}
return btnWidget;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Image Upload Demo'),
),
body: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40.0, left: 10.0, right: 10.0),
child: OutlineButton(
onPressed: () => _openImagePickerModal(context),
borderSide:
BorderSide(color: Theme.of(context).accentColor, width: 1.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.camera_alt),
SizedBox(
width: 5.0,
),
Text('Add Image'),
],
),
),
),
_imageFile == null
? Text('Please pick an image')
: Image.file(
_imageFile,
fit: BoxFit.cover,
height: 300.0,
alignment: Alignment.topCenter,
width: MediaQuery.of(context).size.width,
),
_buildUploadBtn(),
],
),
);
}
}
导入“包装:颤振/材料.省道”;
导入“dart:io”;
将“package:http/http.dart”导入为http;
导入“包:image_picker/image_picker.dart”;
导入“package:mime/mime.dart”;
导入“dart:convert”;
导入“package:http_parser/http_parser.dart”;
导入“包装:toast/toast.dart”;
void main()=>runApp(MyApp());
类MyApp扩展了无状态小部件{
//此小部件是应用程序的根。
@凌驾
小部件构建(构建上下文){
返回材料PP(
标题:“图像上传演示”,
主题:主题数据(原始样本:颜色。粉色),
主页:ImageInput());
}
}
类ImageInput扩展StatefulWidget{
@凌驾
状态createState(){
返回_ImageInput();
}
}
类_ImageInput扩展状态{
//存储图像选择器提供的文件
文件imageFile;
//跟踪文件上载状态的步骤
bool\u=假;
字符串baseUrl=http://YOUR_IPV4_ADDRESS/flutterdemoapi/api.php';
void\u getImage(BuildContext上下文,ImageSource源)异步{
File image=wait ImagePicker.pickImage(源:source);
设置状态(){
_图像文件=图像;
});
//关闭底页
Navigator.pop(上下文);
}
未来上传映像(文件映像)异步{
设置状态(){
_IsUpload=true;
});
//通过查看文件的头字节来查找所选文件的mime类型
最终模拟类型数据=
lookupMimeType(image.path,头字节:[0xFF,0xD8]).split('/');
//初始化多部分请求
最终图像上传请求=
http.MultipartRequest('POST',Uri.parse(baseUrl));
//将文件附加到请求中
final file=wait http.MultipartFile.fromPath('image',image.path,
contentType:MediaType(mimeTypeData[0],mimeTypeData[1]);
//使用请求正文显式传递映像的扩展名
//因为图像选择器有一些错误,所以它混淆了
//文件名为filenamejpge的图像扩展名
//这在服务器端造成了一些需要管理的问题
//或者验证文件扩展名
imageUploadRequest.fields['ext']=mimeTypeData[1];
imageUploadRequest.files.add(文件);
试一试{
final StreamdResponse=等待imageUploadRequest.send();
最终响应=等待http.response.fromStream(流响应);
如果(response.statusCode!=200){
返回null;
}
最终映射responseData=json.decode(response.body);
_重置状态();
返回响应数据;
}捕获(e){
印刷品(e);
返回null;
}
}
void\u startupboading()异步{
最终地图响应=等待上传图像(\u图像文件);
打印(回复);
//检查是否发生任何错误
if(response==null | | response.containsKey(“错误”)){
Toast.show(“图像上传失败!!!”,上下文,
持续时间:Toast.LENGTH_LONG,重力:Toast.BOTTOM);
}否则{
Toast.show(“图像上传成功!!!”,上下文,
持续时间:Toast.LENGTH_LONG,重力:Toast.BOTTOM);
}
}
void _resetState(){
设置状态(){
_isUploading=false;
_imageFile=null;
});
}
void\u OpenImagePickerModel(构建上下文){
最终flatButtonColor=主题.of(上下文).primaryColor;
打印(“调用图像选择器模式”);
showModalBottomSheet(
上下文:上下文,
生成器:(BuildContext上下文){
返回容器(
高度:150.0,
填充:所有边缘设置(10.0),
子:列(
儿童:[
正文(
“选择图像”,
样式:TextStyle(fontWeight:fontWeight.bold),
),
大小盒子(
身高:10.0,
),
扁平按钮(
textColor:flatButtonColor,
子项:文本(“使用摄影机”),
已按下:(){
_getImage(上下文,ImageSource.camera);
},
),
扁平按钮(
textColor:flatButtonColor,
子项:文本(“使用库”),
已按下:(){
_getImage(上下文,ImageSource.gallery);
},
),
],
),
);
});
}
小部件_buildUploadBtn(){
小部件btnWidget=Container();
如果(正在上载){
//正在上载文件,然后显示进度指示器
btnWidget=容器(
边距:仅限边缘集(顶部:10.0),
child:CircularProgressIndicator());
}如果(!\u正在上载&&u图像文件!=null),则为else{
//如果图像由用户拾取,则显示上载btn
btnWidget=容器(
边距:仅限边缘集(顶部:10.0),
孩子:升起按钮(
子项:文本(“上载”),
已按下:(){
_启动加载();
},
颜色:Colors.pinkAccent,
textColor:Colors.white,
),
);
}
返回btnWidget;
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“图像上传演示”),
),
正文:专栏(
儿童:[
填充物(
填充:仅限常量边集(顶部:40.0,左侧:10.0,右侧:10.0),
孩子:大纲按钮(
按下:()=>\u OpenImagePickerModel(上下文),
边界:
BorderSide(颜色:Theme.of(context).accentColor,宽度:1.0),
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:multi_image_picker/multi_image_picker.dart';
void main() => runApp(new MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Asset> images = List<Asset>();
String _error;
@override
void initState() {
super.initState();
}
Widget buildGridView() {
if (images != null)
return GridView.count(
crossAxisCount: 3,
children: List.generate(images.length, (index) {
Asset asset = images[index];
return AssetThumb(
asset: asset,
width: 300,
height: 300,
);
}),
);
else
return Container(color: Colors.white);
}
Future<void> loadAssets() async {
setState(() {
images = List<Asset>();
});
List<Asset> resultList;
String error;
try {
resultList = await MultiImagePicker.pickImages(
maxImages: 300,
);
} on Exception catch (e) {
error = e.toString();
}
// 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;
if (error == null) _error = 'No Error Dectected';
});
}
@override
Widget build(BuildContext context) {
return new MaterialApp(
home: new Scaffold(
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: Column(
children: <Widget>[
Center(child: Text('Error: $_error')),
RaisedButton(
child: Text("Pick images"),
onPressed: loadAssets,
),
Expanded(
child: buildGridView(),
)
],
),
),
);
}
}