Flutter 相册图片多选

1,298 阅读2分钟

前一段项目要做类似微信朋友圈的评论回复功能,要多选图片,当时在网上也找了一下,发现文章并不是太多,就把自己写的也记录一下(主要是我们的项目使用的flutter版本太低了1.17.2的,flutter2.0.1版本之上可使用images_picker插件,一个插件满足您的需求)。 ###插件

dependencies:
  photo:
    path: ./flutter_photo #这个插件pub_dev上也不是最新的,我是把作者发布到git上的拉下来导入到项目中了
  image_picker: ^0.6.7+22

为什么要用两个插件,是因为image_picker 这个插件虽然支持拍照和相册选择,但是图片只能一张一张的选择,photo 是支持图片多选的(但是这个插件好久没更新了)

废话不多说,开始上代码:

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter_app_image_picker/photo_picker_tool.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: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {


  @override
  Widget build(BuildContext context) {

    return Scaffold(
        appBar:AppBar(
            title:Text('PhotoSelectTest')
        ),
        body:
        Container(
            padding: EdgeInsets.fromLTRB(80, 10, 30, 10),
            color: Colors.red,
            child:
            JhPhotoPickerTool(
              lfPaddingSpace: 110,
              callBack: (var img) async{
                print("img-------${File(img[0]).lengthSync()}------");
                print(img.length);
                print(img);
              },
            )
        )

    );
  }
}


import 'package:flutter/material.dart';
import 'package:jxcapp/utils/image_utils.dart';

import 'package:photo/photo.dart';
import 'package:photo_manager/photo_manager.dart';
import 'dart:io';
import 'package:image_picker/image_picker.dart';
import 'package:heic_to_jpg/heic_to_jpg.dart';
const double itemSpace = 10.0;
const double space = 5.0; //上下左右间距
const double deleBtnWH = 20.0;
const Color bgColor = Colors.white;
const int maxCount = 3;// 最大选择图片数量
typedef CallBack = void Function(List imgData);

class JhPhotoPickerTool extends StatefulWidget {
  final double lfPaddingSpace; //外部设置的左右间距
  final CallBack callBack;

  JhPhotoPickerTool({
    this.lfPaddingSpace,
    this.callBack,
  });

  @override
  _JhPhotoPickerToolState createState() => _JhPhotoPickerToolState();
}

class _JhPhotoPickerToolState extends State<JhPhotoPickerTool> {
  List _imgData = List(); //图片list
  List imgDefaultData = List(); //图片list
  List<AssetEntity> imgPicked = [];

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    imgDefaultData.add("selectPhoto_add"); //先添加 加号按钮 的图片
  }

  @override
  void setState(fn) {
    // TODO: implement setState
    super.setState(fn);
    List data = List();
    data.addAll(_imgData);
    // data.removeAt(_imgData.length - 1);
    widget.callBack(data);
  }

  @override
  Widget build(BuildContext context) {
    var kScreenWidth = MediaQuery.of(context).size.width;

    var lfPadding = widget.lfPaddingSpace == null ? 0.0 : widget.lfPaddingSpace;
    var ninePictureW = (kScreenWidth - space * 2 - 2 * itemSpace - lfPadding);
    var itemWH = ninePictureW / maxCount;
    int columnCount = _imgData.length > 6 ? 3 : _imgData.length <= 3 ? 1 : 2;

    return Container(
        color: bgColor,
        width: kScreenWidth - lfPadding,
        height:
            columnCount * itemWH + space * 2 + (columnCount - 1) * itemSpace,
        child: GridView.builder(
            gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
              //可以直接指定每行(列)显示多少个Item
              //一行的Widget数量
              crossAxisCount: 3,
              crossAxisSpacing: itemSpace, //水平间距
              mainAxisSpacing: itemSpace, //垂直间距
              childAspectRatio: 1.0, //子Widget宽高比例
            ),
            physics: NeverScrollableScrollPhysics(),
            padding: EdgeInsets.all(space),
            //GridView内边距
            itemCount: _imgData.length== maxCount?_imgData.length: (_imgData.length + imgDefaultData.length),
            itemBuilder: (context, index) {
              if (_imgData.length == maxCount) {
                return imgItem(index, setState, _imgData, imgPicked);
              } else {
                if (index == _imgData.length) {
                  return addBtn(context, setState, imgDefaultData, imgPicked);
                } else {
                  return imgItem(index, setState, _imgData, imgPicked);
                }
              }
            }));
  }

  /** 添加按钮 */
  Widget addBtn(context, setState, imgData, imgPicked) {
    return GestureDetector(
      child: Container(
        color: Color(0xffF7F7F7),
        padding: EdgeInsets.all(40),
        child: Image.asset(
          ImageUtils.getImgPath('report/report_add_icon'),
          // fit: BoxFit.cover,
        ),
      ),
      onTap: () {
        FocusScope.of(context).requestFocus(FocusNode());
        showModalBottomSheet(
          context: context,
          builder: (BuildContext context) {
            return new Container(
              height: 195.0,
              child: Column(
                children: <Widget>[
                  MaterialButton(
                    height:50,
                    child: Text('拍摄'),
                    onPressed: () async {
                      Navigator.pop(context);
                      var image = await ImagePicker.pickImage(
                          source: ImageSource.camera);
                      print(image);
                      if(image.absolute.path.contains('.he') || image.absolute.path.contains('.HE')){
                        String jpegPath = await HeicToJpg.convert(image.absolute.path);
                        _imgData.insert(_imgData.length, jpegPath);
                      }
                      else{
                        _imgData.insert(_imgData.length, image.absolute.path);
                      }
                      // _imgPicked.add(image);

                      setState(() {});

                    },
                  ),
                  SizedBox(
                    height: 1,
                    child: Container(
                      color: Color(0xffF4F4F4),
                    ),
                  ),
                  MaterialButton(
                    height:50,
                    child: Text('从手机相册选择'),
                    onPressed: () async {
                      pickAsset(context, setState, _imgData, imgPicked);
                      Navigator.pop(context);
                    },
                  ),
                  SizedBox(
                    height: 10,
                    child: Container(
                      color: Color(0xffF4F4F4),
                    ),
                  ),
                  MaterialButton(
                    height:50,
                    child: Text('取消'),
                    onPressed: () {
                      Navigator.pop(context);
                    },
                  ),
                ],
              ),
            );
          },
        ).then((val) {
          print(val);
        });
      },
    );
  }

  /** 多图选择 */
  void pickAsset(context, setState, imgData, imgPicked) async {
    final result = await PhotoPicker.pickAsset(
        context: context,
        pickedAssetList: imgPicked,
        maxSelected: maxCount - _imgData.length,
        pickType: PickType.onlyImage);

    if (result != null && result.isNotEmpty) {
      for (var e in result) {
        var file = await e.file;
//         if (!imgData.contains(file.absolute.path)) {// 如果想避免重复选同一张图片,可以加上这个判断
        if(file.absolute.path.contains('.he') || file.absolute.path.contains('.HE')){// 这个判断的意义请继续往下看
          String jpegPath = await HeicToJpg.convert(file.absolute.path);
          _imgData.insert(_imgData.length, jpegPath);
        }
        else{
          _imgData.insert(_imgData.length, file.absolute.path);
        }

        // }
      }
    }
    setState(() {});
  }

  /** 图片和删除按钮 */
  Widget imgItem(index, setState, imgData, imgPicked) {
    return GestureDetector(
      child: Container(
        color: Colors.transparent,
        child: Stack(alignment: Alignment.topRight, children: <Widget>[
          ConstrainedBox(
            child: Image.file(File(imgData[index]), fit: BoxFit.cover),
            constraints: BoxConstraints.expand(),
          ),
          GestureDetector(
            child: Image.asset(
              ImageUtils.getImgPath('report/report_delete'),//这是我本地的添加图片
              // fit: BoxFit.cover,
            ),
            onTap: () {
              //点击删除按钮
              setState(() {
                _imgData.removeAt(index);
                // imgPicked.removeAt(index);
              });
            },
          )
        ]),
      ),
      onTap: () {
        print("点击第${index}张图片");
      },
    );
  }
}

以上就是我的代码,可能有的朋友就问了heic_to_jpg 这个插件是干什么用的, 苹果heic格式图片不能直接在浏览器上显示,所以我们就需要借用插件转换一下格式,详细请看:

heic:baike.baidu.com/item/HEIC/1… jpg: baike.baidu.com/item/JPEG%E… HEIF & HEVC   juejin.im/post/59ddc1…

到这里还不算结束,安卓还有一个问题,就是系统是安卓11及以上相册打不开,你需要修改你项目中的这个地方,上图:

3146474-7c25853515e5dfd1.png 这里就是去除安卓11的新特性,可以使插件正常使用。

以上就是这篇文章的全部内容了,写的不好的地方还请多多指教!