Flutter从相册选择图片并显示出来,上传到服务器


在Android中从手机相册选择一些图片出来是很常用的功能。Flutter也提供了很好用的第三方库可以帮助我们快速实现这个需求。

实现效果如下

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述

接下来看看该怎么用。

导入依赖包

版本号可以到puv.dev上查找最新的替换上去。

dependencies:
  multi_image_picker: ^4.6.1

multi_image_picker的使用

使用这个插件也很简单。首先导入包

import 'package:multi_image_picker/multi_image_picker.dart';

接着就访问相册选择图片。

  • 先定义一个List<Asset> resultList用于保存选择后的图片信息。
  • MultiImagePicker.pickImages的返回类型是List<Asset>
  • 相关参数使用看代码中的注释
  // 选择照片并上传
  Future<void> uploadImages() async {
    if (resultList == null) {
      resultList = List<Asset>();
    }
    try {
      var tmp = await MultiImagePicker.pickImages(
        // 可选参数, 若resultList不为空,再次打开选择界面的适合,可以显示之前选中的图片信息。 
        selectedAssets: resultList,
        // 选择图片的最大数量
        maxImages: 9,
        // 是否支持拍照
        enableCamera: true,
        materialOptions: MaterialOptions(
          // 显示所有照片,值为 false 时显示相册
            startInAllView: false,
            allViewTitle: '所有照片',
            actionBarColor: '#2196F3',
            textOnNothingSelected: '没有选择照片'),
      );
      if (tmp.length != 0) {
        resultList = tmp;
        setState(() {});
      }
    } on Exception catch (e) {
      e.toString();
    }
  }

这样选择图片的功能就以及做好了。

显示图片

接下来实现显示图片的功能。

使用gridview显示。

因为选择后的图片是一个Asset类型。所以可以使用 AssetThumb显示图片

AssetThumb(
    asset: resultList[index],
    width: 300,
    height: 300,
)
 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
    title: Text('发动态'),
    actions: [
      IconButton(
          icon: Icon(Icons.send),
          onPressed: () async {


          })
    ],
      ),
      body: Container(
    padding: EdgeInsets.all(5),
    child: ListView(
      children: [
        TextField(
          controller: _controller,
          decoration: InputDecoration(
              border: OutlineInputBorder(), hintText: '说点什么……'),
          maxLines: 7,
        ),
        Row(
          children: [
            RaisedButton(
              onPressed: () {
                uploadImages();
              },
              child: Text('选择图片'),
            ),
          ],
        ),
        Container(
          width: double.infinity,
          height: 1000,
          child: GridView.builder(
            padding: EdgeInsets.all(0),
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 3,
                crossAxisSpacing: 2,
                mainAxisSpacing: 2),
            itemBuilder: (BuildContext context, int index) {
              return _createGridViewItem(
                  AssetThumb(
                    asset: resultList[index],
                    width: 300,
                    height: 300,
                  ),
                  index);
            },
            itemCount: resultList.length,
          ),
        )
      ],
    ),
      ),
    );
  } 

_createGridViewItem(widget, index) {
    return Container(
      height: 100,
      width: 100,
      padding: EdgeInsets.all(0),
      margin: EdgeInsets.all(0),
      child: Stack(
        children: [
          widget,
          Positioned(
            top: 0,
            right: 0,
            child: GestureDetector(
              onTap: () {
                setState(() {
                  resultList.removeAt(index);
                });
              },
              child: Icon(
                Icons.close,
                color: Colors.grey,
              ),
            ),
          )
        ],
      ),
    );
  }

上传图片

导入依赖dio

dependencies:  
  dio: ^3.0.10
  dio_log: ^1.3.5

dio中提供了文件上传的方式,具体可以去看官方文档。

  • MultipartFile 是Dio中用户文件上传的类
  • 如果一次性需要传多个图片,可以用一个List数组保存
          List<MultipartFile> files = List();
					//  resultList就是之前获取选择图片的List
              for (int i = 0; i < resultList.length; i++) {
                // 获取 ByteData
                ByteData byteData = await resultList[i].getByteData();
                List<int> imageData = byteData.buffer.asUint8List();

                MultipartFile multipartFile = MultipartFile.fromBytes(
                  imageData,
                  // 文件名
                  filename: 'some-file-name.jpg',
                  // 文件类型
                  contentType: MediaType("image", "jpg"),
                );

                files.add(multipartFile);
              }

封装到FormData里面。

  • 这里的image就是后端接口中接收文件的参数名。如果传入的是一个数组,则会自动加上[]
              FormData formData = FormData.fromMap({
                // 后端接口的参数名称
                "image": files,
              });

之后就可以上传了。

              HttpUtils.instance.post("/upload", formData,
                  success: (response) {
                      //这部分是对相应结果的处理,大家可以根据自己返回的数据类型进行修改
                    if (response['code'] == 200) {
                      List list = response['data'];

                      for (var i = 0; i < list.length; i++) {
                        if (i != 0) urls += "¥";
                        urls += list[i];
                      }
                    }

                  });

可能遇到的问题

理论上使用multi_image_picker是不用管权限问题的,但是如果遇到了Permission denied的情况的话,则打开
android\app\src\main\AndroidManifest.xml这个文件
然后加上这几个权限

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="cn.jxj4869.flutter_imagepick_demo">

    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.CAMERA" />

完整代码已经上传GitHubhttps://github.com/jiang4869/CSDNBlogCode/tree/master/flutter_imagepick_demo,喜欢的话可以start一些。这个demo是动态上传界面。可以发送文字和图片信息。

拒绝白嫖,从点一键三连开始

猜你喜欢

转载自blog.csdn.net/qq_43058685/article/details/113773694