Flutter图片表单字段插件image_form_field的使用
在Flutter中处理图片上传时,可以使用image_form_field
插件来简化操作。此插件允许你在Form
中集成图片上传功能,并提供了灵活的自定义选项。
使用方法
为了完全自定义照片上传字段,需要使用几个回调函数和类。通常情况下,你会将远程来源的照片与本地上传的照片混合在一起,因此一个适配层会非常有用:
class ImageInputAdapter {
/// 初始化时只能从URL或文件中选择其一。
ImageInputAdapter({
this.file,
this.url,
}) :
assert(file != null || url != null),
assert(file != null && url == null),
assert(file == null && url != null);
/// 图片文件
final File file;
/// 远程图片的直接链接
final String url;
/// 渲染来自文件或远程源的图片。
Widget widgetize() {
if (file != null) {
return Image.file(file);
} else {
return FadeInImage(
image: NetworkImage(url),
placeholder: AssetImage("assets/images/placeholder.png"),
fit: BoxFit.contain,
);
}
}
}
接下来,在Flutter的Form
中使用ImageFormField
:
import 'package:image_form_field/image_form_field.dart';
ImageFormField<ImageInputAdapter>(
previewImageBuilder: (_, ImageInputAdapter image) =>
image.widgetize(),
buttonBuilder: (_, int count) =>
Container(
child: Text(
count == null || count < 1 ? "上传图片" : "继续上传"
)
),
initializeFileAsImage: (File file) =>
ImageInputAdapter(file: file),
initialValue: existingPhotoUrl == null ? null : [ImageInputAdapter(url: existingPhotoUrl)],
// 即使`shouldAllowMultiple`为true,`images`始终是一个声明类型的列表(即`ImageInputAdapter`)。
onSaved: (images) => _images = images,
)
完整的示例代码可以在这里找到。
参数说明
以下是ImageFormField
的主要参数说明(T表示声明的显示类型,例如ImageFormField<T>
):
名称 | 类型 | 是否必需 | 描述 |
---|---|---|---|
previewImageBuilder |
Widget Function(BuildContext, T) |
是 | 如何在上传按钮下方渲染图片 |
buttonBuilder |
Widget Function(BuildContext, [int]) |
是 | 按钮的显示方式。不要使用FlatButton ;按钮已经被包裹在一个GestureRecognizer 中 |
initializeFileAsImage |
T Function(File) |
是 | 将上传转换为适配器类 |
controller |
ImageFieldController |
否 | 直接访问当前显示或上传的图片 |
initialValue |
List |
否 | 初始渲染时显示的图片;如果initialValue 在initState 或其他非传递方法中设置,则不要渲染字段直到值被设置 |
onSaved |
VoidCallback Function(List) |
否 | 当表单保存时处理上传/远程图片 |
validator |
VoidCallback Function(List) |
否 | 当表单验证时处理上传/远程图片 |
errorTextStyle |
TextStyle |
否 | 控制字段无效时文本的显示方式;通常最好使用Theme.of(context).inputDecorationTheme.errorStyle |
autoValidate |
bool |
否 | 字段是否应自动验证(默认为false) |
shouldAllowMultiple |
bool |
否 | 字段是否允许多张图片上传(默认为true) |
感谢
感谢AllGo为该项目提供了初始支持。
完整示例代码
以下是一个完整的示例代码,展示了如何使用image_form_field
插件进行图片上传:
import 'package:flutter/material.dart';
import 'package:image_form_field/image_form_field.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'upload_button.dart';
import 'image_input_adapter.dart';
void main() => runApp(new MyApp());
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return new MaterialApp(
title: 'Flutter 图片演示',
home: new MyHomePage(),
);
}
}
class BlogImage {
const BlogImage({
@required this.storagePath,
@required this.originalUrl,
@required this.bucketName,
this.id,
});
final String storagePath;
final String originalUrl;
final String bucketName;
final String id;
static String get collectionPath => "blogImages";
create() {
return Firestore.instance.collection(collectionPath).document().setData({
"storagePath": storagePath,
"originalUrl": originalUrl,
"bucketName": bucketName,
});
}
static Future<BlogImage> fromUrl(String url) async {
final images = await Firestore.instance
.collection(collectionPath)
.where("originalUrl", isEqualTo: url)
.getDocuments();
if (images.documents.isNotEmpty) {
final i = images.documents.first.data;
return BlogImage(
storagePath: i["storagePath"],
originalUrl: i["originalUrl"],
bucketName: i["bucketName"],
id: images.documents.first.documentID,
);
}
return null;
}
Future delete() async {
FirebaseStorage.instance.ref().child(storagePath).delete();
return Firestore.instance.collection(collectionPath).document(id).delete();
}
}
class _UploadForm extends StatefulWidget {
_UploadForm(this.existingImages);
final List<BlogImage> existingImages;
[@override](/user/override)
State<StatefulWidget> createState() => _UploadFormState();
}
class _UploadFormState extends State<_UploadForm> {
final _formKey = GlobalKey<FormState>();
List<ImageInputAdapter> _images;
void submit() {
if (_formKey.currentState.validate()) {
_formKey.currentState.save();
var snackbarText = "上传成功";
try {
// 新图片
_images?.where((i) => i.isFile)?.forEach((i) async {
final photo = await i.save();
BlogImage(
storagePath: photo.refPath,
originalUrl: photo.originalUrl,
bucketName: photo.bucketName,
).create();
});
// 删除的图片
widget.existingImages
?.where((r) => !_images.any((m) => m.url == r.originalUrl))
?.forEach((i) {
BlogImage.fromUrl(i.originalUrl).then((b) => b?.delete());
});
} catch (e) {
print(e);
snackbarText = "无法保存,请稍后再试。";
} finally {
Scaffold.of(context).showSnackBar(SnackBar(content: Text(snackbarText)));
}
}
}
[@override](/user/override)
Widget build(BuildContext context) {
final bool shouldAllowMultiple = true;
return Form(
key: _formKey,
child: ListBody(
children: [
ImageFormField<ImageInputAdapter>(
shouldAllowMultiple: shouldAllowMultiple,
onSaved: (val) => _images = val,
initialValue: widget.existingImages
.map((i) => ImageInputAdapter(url: i.originalUrl))
.toList()
.cast<ImageInputAdapter>(),
initializeFileAsImage: (file) => ImageInputAdapter(
file: UploadableImage(
file,
storagePath: "appImages",
),
),
buttonBuilder: (_, count) =>
PhotoUploadButton(count: count, shouldAllowMultiple: shouldAllowMultiple),
previewImageBuilder: (_, image) => image.widgetize(),
),
FlatButton(
onPressed: submit,
child: const Text("更新资料"),
)
],
),
);
}
}
class MyHomePage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(centerTitle: true, title: const Text("上传图片")),
body: SingleChildScrollView(
// 提供现有的图片作为第一个参数
child: _UploadForm(List<BlogImage>()),
),
);
}
}
更多关于Flutter图片表单字段插件image_form_field的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter图片表单字段插件image_form_field的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
image_form_field
是一个用于 Flutter 的插件,它允许用户在表单中选择和上传图片。这个插件通常用于需要用户上传图片的场景,比如用户头像、产品图片等。
安装
首先,你需要在 pubspec.yaml
文件中添加 image_form_field
插件的依赖:
dependencies:
flutter:
sdk: flutter
image_form_field: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
基本用法
以下是一个简单的示例,展示了如何使用 image_form_field
插件:
import 'package:flutter/material.dart';
import 'package:image_form_field/image_form_field.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Image Form Field Example'),
),
body: ImageFormFieldExample(),
),
);
}
}
class ImageFormFieldExample extends StatefulWidget {
@override
_ImageFormFieldExampleState createState() => _ImageFormFieldExampleState();
}
class _ImageFormFieldExampleState extends State<ImageFormFieldExample> {
final _formKey = GlobalKey<FormState>();
File? _image;
@override
Widget build(BuildContext context) {
return Form(
key: _formKey,
child: Column(
children: [
ImageFormField(
onSaved: (File? image) {
_image = image;
},
validator: (File? image) {
if (image == null) {
return 'Please select an image';
}
return null;
},
),
SizedBox(height: 20),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
_formKey.currentState!.save();
// 在这里处理图片上传逻辑
if (_image != null) {
print('Image selected: ${_image!.path}');
}
}
},
child: Text('Submit'),
),
],
),
);
}
}
参数说明
onSaved
: 当表单保存时调用的回调函数,返回用户选择的图片文件。validator
: 用于验证用户是否选择了图片。如果用户没有选择图片,可以返回一个错误消息。decoration
: 用于自定义ImageFormField
的外观,比如提示文本、边框等。initialValue
: 设置初始的图片文件。maxWidth
和maxHeight
: 设置图片的最大宽度和高度。imageQuality
: 设置图片的质量,范围是 0 到 100。
处理图片上传
在 onSaved
回调中,你可以获取用户选择的图片文件,并将其上传到服务器。你可以使用 http
或 dio
等库来处理文件上传。
void _uploadImage(File image) async {
var request = http.MultipartRequest('POST', Uri.parse('https://example.com/upload'));
request.files.add(await http.MultipartFile.fromPath('file', image.path));
var response = await request.send();
if (response.statusCode == 200) {
print('Image uploaded successfully');
} else {
print('Failed to upload image');
}
}