基于Flutter实现图片选择和图片上传

目录
  • 内容简介
  • 图片选择插件
  • 权限申请
  • UI 改造
  • 图片上传

内容简介

本篇将介绍 Flutter 中如何完成图片上传,以及上传成功后的表单提交。涉及的知识点如下:

  • 图片选择插件wechat_assets_picker的使用。
  • 图片选择 iOS 和安卓的应用权限配置。
  • 图片选择组件的封装。
  • 图片上传接口的封装。
  • 添加和编辑页面中图片上传实现。

图片选择插件

Flutter 的图片选择插件很多,包括了官方的 image_pickermulti_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 的后台代码。接口地址分别为:

  • 单张图片上传接口地址:http://localhost:3900/api/upload/image ,Post 请求,字段名为image,成功后返回图片文件id
  • 图片获取接口:http://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 = 'http://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图片选择上传的资料请关注我们其它相关文章!

(0)

相关推荐

  • Flutter Image实现图片加载

    Image 简介 Android ios 原生中使用 ImageView 来加载显示图片. 在flutter 中通过Image来加载并显示图片. 所有的widget并不是直接绘制图片的,而是控制的图片的主要属性的容器,负责绘制的是RenderObject,他们中间是通过ElementTree来联系起来.有了这个基础后,所有的widget都不会提供画布(canvas)来直接绘制image RawImage 这是一个最基础图片容器Widget. Image 这是一个通用包装类,它包装了RawImag

  • Flutter 生成图片保存至相册的示例

    目录 基本思路 添加依赖 实现代码 遇到一个需求,需要用 Flutter 生成图片,最终实现的效果如下: 基本思路 使用 Canvas 绘制图片中各元素,然后使用 PictureRecorder 进行记录生成. 添加依赖 qr_flutter: ^3.1.0 image_gallery_saver: ^1.2.2 fluttertoast: ^4.0.0 实现代码 import 'dart:ui' as ui; import 'dart:ui'; import 'package:flutter/

  • Android选择与上传图片之ImagePicker教程

    效果图: 后来又出了两篇,也可以看一下 Android选择与上传图片之PictureSelector教程 Android选择与上传图片之Matisse教程 添加依赖: 选择图片:compile 'com.lzy.widget:imagepicker:0.5.4' github地址:https://github.com/jeasonlzy/ImagePicker 上传文件:compile 'com.zhy:okhttputils:2.6.2' github地址:https://github.com

  • Android实现图片选择上传功能实例

    效果图: 添加依赖: 选择图片:compile 'com.lzy.widget:imagepicker:0.5.4' github地址:https://github.com/jeasonlzy/ImagePicker 上传文件:compile 'com.zhy:okhttputils:2.6.2' github地址:https://github.com/hongyangAndroid/okhttputils MainActivity.java package com.yechaoa.upload

  • Android选择与上传图片之PictureSelector教程

    效果图: [注意]Demo已更新到最新版本,并稍作调整. 之前出过一篇 Android选择与上传图片之ImagePicker教程,这个是okgo作者出的,就一般需求来讲是够了,但是没有压缩,需要自己去搞. 后来业务需求提升,页面要美,体验要好,便不是那么满足需求了,所幸在github上找到PictureSelector(然后当时没多久Matisse就开源了-可以看这里 Android选择与上传图片之Matisse教程),也不用自己再撸一个了,下面来介绍介绍PictureSelector gith

  • Android选择与上传图片之Matisse教程

    效果图: 就目前效果图来看,好像也没什么毛病哈,其实我这个集成的过程是有点坎坷的. 而且,功能也不算是很齐全吧-主要体现在以下几个点 没有回调之后的预览 选择之后不能删除已选 已选择的图片再次选择不能带过去 剪裁 压缩 权限 Glide版本过低 但是,也是有特点的 MD风格 白天模式和夜间模式 其他与同类相比也真的没什么了,唯一背书 就是知乎团队出的呗.. 相比之下,昨天出的Android选择与上传图片之PictureSelector教程就更加友好和人性化了. 下面来说说集成遇到的问题以及解决方

  • 基于Flutter实现图片选择和图片上传

    目录 内容简介 图片选择插件 权限申请 UI 改造 图片上传 内容简介 本篇将介绍 Flutter 中如何完成图片上传,以及上传成功后的表单提交.涉及的知识点如下: 图片选择插件wechat_assets_picker的使用. 图片选择 iOS 和安卓的应用权限配置. 图片选择组件的封装. 图片上传接口的封装. 添加和编辑页面中图片上传实现. 图片选择插件 Flutter 的图片选择插件很多,包括了官方的 image_picker,multi_image_picker(基于2.0出了 multi

  • JS移动端/H5同时选择多张图片上传并使用canvas压缩图片

    最近在做一个H5的项目,里边涉及到拍照上传图片的功能以及识别图片的功能,这里对识别图片的功能不做赘述,不属本文范畴.我在做完并上线项目后,同事跟我提了一个要求是可不可以同时选择多张图片上传,我做的时候的想法是如果给file表单加了 multiple 属性就没有办法调用手机的摄像头拍照了,如果不加,就无法同时选择多张图片,于是我就照实跟同事说了这个情况.但回头一想,单张图片可以上传,那多张图片呢?于是就有了本文的内容. HTML5定义了 FileReader 作为文件 API 的重要成员用于读取文

  • Vue.js 2.0 移动端拍照压缩图片预览及上传实例

    在学习和使用Vue.js 2.0 的过程中遇到不少不一样的地方,本来移动端开发H5应用,准备将mui框架和Vue.js+vue-router+vuex 全家桶结合起来使用,但是在拍照上传的实现过程中遇到了无法调用plus的H5+接口的问题,所以最后拍照上传功能还是使用input file方式里解决的.但是内心还是不甘心的,由于项目进度推进,迭代版本,所以不得不放弃,后续可能我将此功能使用调用H5+接口实现. 首先我来讲我实现这个拍照预览压缩上传的思路,准确的说应该是拍照或选择图片压缩之后预览及上

  • jsp中点击图片弹出文件上传界面及实现预览实例详解

    jsp中点击图片弹出文件上传界面及实现预览实例详解 花了两天时间琢磨一下图片预览的功能 任务需求如下: 1:jsp页面中有一个图片(pic_1) 2:点击图片弹出类似于资源管理器的界面 3:选择完某一个图片之后在pic_1处预览 我在IE8上试验下面这段代码,可以实现上述功能,没有在别的浏览器中测试,如果各位朋友知道多种浏览器的支持方法,请赐教,共同学习,谢谢. <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN&qu

  • 微信小程序实现图片轮播及文件上传

     微信小程序实现图片轮播及文件上传 刚刚接触微信小程序,看着网上的资源写了个小例子,本地图片轮播以及图片上传. 图片轮播: index.js <span style="font-size:14px;">var app = getApp() Page({ data:{ mode: 'aspectFit', // src:'../images/timg1.jpg', imgUrls:[ '../images/1.jpg', '../images/2.jpg', '../imag

  • Android Retrofit实现多图片/文件、图文上传功能

    什么是 Retrofit ? Retrofit是Square开发的一个Android和Java的REST客户端库.这个库非常简单并且具有很多特性,相比其他的网络库,更容易让初学者快速掌握.它可以处理GET.POST.PUT.DELETE-等请求,还可以使用picasso加载图片. 一.再次膜拜下Retrofit Retrofit无论从性能还是使用方便性上都很屌!!!,本文不去介绍其运作原理(虽然很想搞明白),后面会出专题文章解析Retrofit的内部原理:本文只是从使用上解析Retrofit实现

  • AJAX实现图片预览与上传及生成缩略图的方法

    要实现功能,上传图片时可以预览,因还有别的文字,所以并不只上传图片,实现与别的文字一起保存,当然上来先上传图片,然后把路径和别的文字一起写入数据库:同时为 图片生成缩略图,现只写上传图片方法,文字在ajax里直接传参数就可以了,若要上传多图,修改一下就可以了. 借鉴了网上资料,自己写了一下,并不需要再新加页面,只在一个页面里就OK啦. JS代码: //ajax保存数据,后台方法里实现此方法 function SaveData() { filename = document.getElementB

  • Struts2中图片以base64方式上传至数据库

    1.页面 这里输入代码 <div> <span id="uploadImg" style="margin:50px;background-color:#ddd;display:inline-block;height:130px;width:200px;"> <span style="color:#bbb;font-weight:600;border:2px #ccc dashed;font-size:20px;text-ali

  • C#判断上传文件是否是图片以防止木马上传的方法

    很多时候木马程序会伪装成其他格式的文件上传到网站,最常见的如图片格式.本文就以C#为例讲述C#判断上传文件是否是图片以防止木马上传的方法,具体方法如下: 方法一:用image对象判断是否为图片 /// <summary> /// 判断文件是否为图片 /// </summary> /// <param name="path">文件的完整路径</param> /// <returns>返回结果</returns> pu

  • SpringMVC图片文件跨服务器上传

    图片文件跨服务器上传(我使用的公司云桌面作为上传服务器,自己的笔记本作为存储服务器测试的) 一.上传服务器: 1.pom文件(使用jersey插件) <!-- 上传组件包 --> <dependency> <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> <version>1.3.1</version&g

随机推荐