Flutter ——图片九宫格,多图片批量上传(图片选择采用官方image_picker实现,批量上传采用dio,消息提示)

需求:实现一个九宫格的效果,要求能够多选照片。
具体描述:
1.实现类似微信九宫格,没图片的时候有一张添加图片,点击该图片可以在相册中选择,当图片未满9个的时候,该图片一直跟在最后,当图片满足9个的时候该添加图片消失。点击右上角X可以移除图片
2.当点击小图的时候能够进行放大的预览,点击大图,预览消失。
3.图片能够进行批量上传,上传的时候进行图片压缩上传

采用的插件
dio: ^4.0.0
fluttertoast: ^8.0.8
image_picker: ^0.8.4+1

#用到的图片放在images文件夹下面
delete.png
addphoto.png


// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// ignore_for_file: public_member_api_docs

import 'dart:io';
import 'package:app_flutter/common/global.dart';
import 'package:dio/dio.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';

class ImageUploadRoute extends StatefulWidget {
  ImageUploadRoute({Key? key, this.title}) : super(key: key);
  final String? title;
  @override
  _ImageUploadState createState() => _ImageUploadState();
}

class _ImageUploadState extends State<ImageUploadRoute> {
  //编辑文本
  late TextEditingController _controller;

  //图片上传相关
  String  _title="图片上传";
  List<XFile> _imageFileList=List.empty(growable: true);//存放选择的图片
  final ImagePicker _picker = ImagePicker();
  int maxFileCount=9;//最大选择图片数量
  dynamic _pickImageError;
  int _bigImageIndex=0;//选中的需要放大的图片的下标
  bool _bigImageVisibility=false;//是否显示预览大图


  //获取当前展示的图的数量
  int getImageCount() {
    if(_imageFileList.length<maxFileCount){
      return _imageFileList.length+1;
    }else{
      return _imageFileList.length;
    }
  }

  Widget _handlePreview() {
    return _previewImages();
  }
  Widget _previewImages() {
    return GridView.builder(
      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
        crossAxisCount:3,//每行三个
        childAspectRatio: 1.0,//宽高比1:1
      ),
      itemBuilder: (context,index){
        if(_imageFileList.length<maxFileCount){//没选满
          if(index<_imageFileList.length){//需要展示的图片
            return Stack( //层叠布局 图片上面要有一个删除的框
              alignment: Alignment.center,
              children: [
                Positioned(
                    top:0.0 ,
                    left: 0.0,
                    right: 0.0,
                    bottom: 0.0,
                    child:GestureDetector(
                      child: Image.file(File(_imageFileList[index].path),fit:BoxFit.cover ),
                      onTap:()=>showBigImage(index) ,
                    )
                ),
                Positioned(
                  top:0.0,
                  right: 0.0,
                  width: 20,
                  height: 20,
                  child:GestureDetector(child: SizedBox(child:  Image.asset('images/delete.png'),),
                    onTap:()=>_removeImage(index), ),
                ),

              ],
            );
            //return Image.file(File(_imageFileList[index].path),fit:BoxFit.cover ,) ;
          }else{//显示添加符号
            return GestureDetector( //手势包含添加按钮 实现点击进行选择图片
              child:Image.asset('images/addphoto.png'),
              onTap: ()=>_onImageButtonPressed(//执行打开相册
                ImageSource.gallery,
                context: context,
                imageQuality: 40,//图片压缩
              ),
            );
          }
        }else {//选满了
          return Stack( //层叠布局 图片上面要有一个删除的框
            alignment: Alignment.center,
            children: [
              Positioned(
                top:0.0 ,
                left: 0.0,
                right: 0.0,
                bottom: 0.0,
                child: GestureDetector(
                  child: Image.file(File(_imageFileList[index].path),fit:BoxFit.cover ),
                  onTap:()=>showBigImage(index) ,
                ),
              ),
              Positioned(
                top:0.0,
                right: 0.0,
                width: 20,
                height: 20,
                child:GestureDetector(child: SizedBox(child:  Image.asset('images/delete.png'),),
                  onTap:()=>_removeImage(index), ),
              ),

            ],
          ) ;
        }
      },
      itemCount: getImageCount(),);
  }




  void _onImageButtonPressed(ImageSource source, {BuildContext? context,double? maxHeight,double? maxWidth,int? imageQuality}) async {
    try {
      final pickedFileList = await _picker.pickMultiImage(
        maxWidth: maxWidth,
        maxHeight: maxHeight,
        imageQuality: imageQuality,
      );
      setState(() {
        //pickedFileList.e
        if(_imageFileList.length<maxFileCount){//小于最大数量
          if((_imageFileList.length+(pickedFileList?.length??0))<=maxFileCount){//加上新选中的不超过最大数量
            pickedFileList!.forEach((element) {
              _imageFileList.add(element);
            });
          }else {//否则报错
            Global.showCenterToast("超过可选最大数量!自动移除多余的图片");
            int avaliableCount=maxFileCount-_imageFileList.length;
            for(int i=0;i<avaliableCount;i++){
              _imageFileList.add(pickedFileList![i]);
            }

          }
        }

      });
    } catch (e) {
      setState(() {
        Global.showCenterToast("$_pickImageError");//出现错误的话报错
        _pickImageError = e;
      });
    }

  }

  //移除图片
  void _removeImage(int index){

    setState(() {
      _imageFileList.removeAt(index);
    });
  }

  //通过双击小图的时候获取当前需要放大预览的图的下标
  void showBigImage(int index){
    setState(() {
      _bigImageIndex=index;
      _bigImageVisibility=true;
    });
  }
  //通过大图的双击事件 隐藏大图
  void hiddenBigImage(){
    setState(() {
      _bigImageVisibility=false;
    });
  }

  //展示大图
  Widget? displayBigImage(){
    if(_imageFileList.length>_bigImageIndex){
      return Image.file(File(_imageFileList[_bigImageIndex].path),fit:BoxFit.fill);
    }else{
      return null;
    }
  }



  //图片上传
  _upLoadImage() async {
    List<dynamic> _imgListUpload  = [];
    _imageFileList.forEach((element) {//遍历图片 加入到dio的批量文件里面
      _imgListUpload.add( MultipartFile.fromFileSync(element.path, filename: element.name));
    });
    var formData= FormData.fromMap({
      'files': _imgListUpload,//批量的图片
      'WAREHOUSEID':'TEST', //其他的参数
      'ORDERNO':'HZ00000000001'
    });
    try{
      Dio dio = new Dio();
      var respone = await dio.post<String>("http://192.168.1.21:8080/FlutterService/UploadImages", data: formData);
      if (respone.statusCode == 200) {
        Global.showCenterToast("上传成功!");
      }
    }catch (e) {
      Global.showCenterToast("上传失败!");
    }

  }



  //初始化的时候打开定位相关
  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();

  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }


  //页面的控件布局
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(title: Text(_title),),
        body:Stack(
          children: [
            Positioned(//占满屏幕
                top: 0,
                bottom: 0,
                left: 0,
                right: 0,
                child: Column(
                  children: [
                    TextField(
                      maxLines: 10,
                      minLines: 3,
                      controller:_controller,
                      decoration:InputDecoration(
                        border:InputBorder.none ,
                        fillColor:Colors.white ,
                        filled: true,
                        hintText: "签收情况",
                      ),
                    ),
                    SizedBox(
                      height: 400,
                      child: _handlePreview(),
                    ),
                    SizedBox(width: double.infinity,
                      height: 50,
                      child:ElevatedButton(
                        style: ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20)),
                        onPressed: _upLoadImage,
                        child: const Text('确定'),
                      ),
                    ),
                  ],
                )),

            Positioned(
              top: 0,
              bottom: 0,
              left: 0,
              right: 0,
              child:Visibility(
                  visible: _bigImageVisibility,
                  child: GestureDetector(
                    child:displayBigImage(),
                    onTap: hiddenBigImage,
                  )

              ),
            ),
          ],
        )

    );
  }

}





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

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值