内容简介
本篇将介绍 flutter 中如何完成图片上传,以及上传成功后的表单提交。涉及的知识点如下:
- 图片选择插件
wechat_assets_picker
的使用。 - 图片选择 ios 和安卓的应用权限配置。
- 图片选择组件的封装。
- 图片上传接口的封装。
- 添加和编辑页面中图片上传实现。
图片选择插件
flutter 的图片选择插件很多,包括了官方的 image_picker
,multi_image_picker
(基于2.0出了 multi_image_picker2
)等等。为了寻找合适的图片选择插件,找了好几个,发现了一个仿微信的图片选择插件 wechat_assets_picker
,看评分和 github的star都不错,先来试用一下。
权限申请
先上了一个简单的 demo,直接调用:
final list<assetentity> assets = await assetpicker.pickassets(context);
结果发现闪退了!!!难道是插件有bug?
bug.jpg
哦,想起来了!忘记设置图片获取权限了!ios 在 runner
的 info.plist
文件增加如下内容:
<key>nsapptransportsecurity</key> <dict> <key>nsallowsarbitraryloads</key> <true/> </dict> <key>nsphotolibraryusagedescription</key> <string>获取图片及使用相册拍照以便上传动态图片。</string>
安卓在app/profile/androidmanifest.xml
和 app/debug/androidmanifest.xml
中增加如下内容:
<uses-permission android:name="android.permission.read_external_storage"/> <uses-permission android:name="android.permission.write_external_storage"/> <uses-permission android:name="android.permission.access_media_location"/>
再次运行,完美!我们都是这么跑 demo 的不是?
选择图片.jpg
ui 改造
我们将动态的添加和编辑修改为选择图片的方式,原先的输入框不能用了,需要更改为图片选择,考虑图片选择会经常用,封装一个通用的单图选择组件。
static widget imagepicker( string formkey, valuechanged<string> ontapped, { file imagefile, string imageurl, double width = 80.0, double height = 80.0, }) { return gesturedetector( child: container( margin: edgeinsets.all(10), alignment: alignment.center, decoration: boxdecoration( color: colors.grey[300], border: border.all(width: 0.5, style: borderstyle.solid), borderradius: borderradius.all(radius.circular(4.0)), ), child: _getimagewidget(imagefile, imageurl, width, height), width: width, height: height, ), ontap: () { ontapped(); }, ); } static widget _getimagewidget( file imagefile, string imageurl, double width, double height) { if (imagefile != null) { return image.file( imagefile, fit: boxfit.cover, width: width, height: height, ); } if (imageurl != null) { return cachednetworkimage( imageurl: imageurl, fit: boxfit.cover, width: width, height: height, ); } return icon(icons.add_photo_alternate); }
这里考虑图片选择组件的占位图片可能来自网络,也可能是文件,因此做了不同的处理。优先显示文件图片,其次是网络图片,若都没有则显示一个添加图片的图标。
之前的动态表单 dynamic_form.dart
也需要进行相应的调整,包括接收图片参数,图片处理函数,并且将之前的图片文本框改为图片选择组件,点击该组件时调用wechat_assets_picker
插件提供的assetpicker.pickassets
方法,限制最大可选则图片为1张。
list<widget> _getform(buildcontext context) { list<widget> widgets = []; formdata.foreach((key, formparams) { widgets.add(formutil.textfield(key, formparams['value'], controller: formparams['controller'] ?? null, hinttext: formparams['hinttext'] ?? '', prefixicon: formparams['icon'], onchanged: handletextfieldchanged, onclear: handleclear)); }); widgets.add(formutil.imagepicker( 'imageurl', () { _pickimage(context); }, imagefile: imagefile, imageurl: imageurl, )); widgets.add(buttonutil.primarytextbutton( buttonname, handlesubmit, context, width: mediaquery.of(context).size.width - 20, )); return widgets; } void _pickimage(buildcontext context) async { final list<assetentity> assets = await assetpicker.pickassets(context, maxassets: 1); if (assets.length > 0) { file file = await assets[0].file; handleimagepicked(file); } }
看看效果怎么样?看起来一切正常,接下来看如何上传。
屏幕录制2021-07-10 下午4.51.51.gif
图片上传
图片上传和获取接口之前已经完成,可以先拉取最新的后台代码:基于 expressjs 的后台代码。接口地址分别为:
- 单张图片上传接口地址:https://localhost:3900/api/upload/image ,post 请求,字段名为
image
,成功后返回图片文件id
。 - 图片获取接口:https://localhost:3900/api/upload/image/:id ,利用图片文件
id
即可获取图片文件流。
dio 提供了formdata
的方式上传文件,示例代码如下:
// 单个文件上传 var formdata = formdata.frommap({ 'name': 'wendux', 'age': 25, 'file': await multipartfile.fromfile('./text.txt',filename: 'upload.txt') }); response = await dio.post('/info', data: formdata); // 多个文件上传 formdata.frommap({ 'files': [ multipartfile.fromfilesync('./example/upload.txt', filename: 'upload.txt'), multipartfile.fromfilesync('./example/upload.txt', filename: 'upload.txt'), ] });
我们可以利用这种方式完成图片的上传。图片上传属于一个公共的服务,我们新建一个 upload_service.dart
文件,用于管理所有上传接口。当前只有一个上传单个文件的方法,从图片文件获取文件路径构建 multipartfile
对象即可,如下所示。
import 'dart:io'; import 'package:dio/dio.dart'; class uploadservice { static const string uploadbaseurl = 'https://localhost:3900/api/upload/'; static future uploadimage(string key, file file) async { formdata formdata = formdata.frommap({key: await multipartfile.fromfile(file.path)}); var result = await dio().post(uploadbaseurl + 'image', data: formdata); return result; } }
接下来就是处理提交事件了,这里添加和编辑处理逻辑会有些不同:
- 添加时需要校验图片文件是否为空,为空则提示需要上传文件;
- 编辑时,本身是一个 原数据的url,若图片文件为空,此时不需要向后台上传图片,也不需要将图片原有的 url上传 (后台代码只存储图片文件的 id,由前端拼接完整地址)。若图片文件不为空,则需要提交数据到后台。如果做得体验更优和节省后端请求,可以比较新表单数据和原表数据是否相同,若没有改变则无需提交数据请求。
提交时,我们需要先上传图片,图片上传成功后将图片文件 id
放入到提交的表单数据里在提交新增或更新接口中。添加时的提交代码如下所示:
_handlesubmit() async { //其他表单校验 if (_imagefile == null) { dialogs.showinfo(this.context, '图片不能为空'); return; } easyloading.showinfo('请稍候...', masktype: easyloadingmasktype.black); try { string imageid; var imageresponse = await uploadservice.uploadimage('image', _imagefile); if (imageresponse.statuscode == 200) { imageid = imageresponse.data['id']; } if (imageid == null) { dialogs.showinfo(this.context, '图片上传失败'); return; } map<string, string> newformdata = {}; _formdata.foreach((key, value) { newformdata[key] = value['value']; }); //新增时将图片 id 放入提交表单中 newformdata['imageurl'] = imageid; // 省略提交代码 } // ... //省略异常处理代码 }
以上就是基于flutter实现图片选择和图片上传的详细内容,更多关于flutter图片选择上传的资料请关注<计算机技术网(www.ctvol.com)!!>其它相关文章!
需要了解更多c/c++开发分享基于Flutter实现图片选择和图片上传,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/1074188.html