You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter单图片上传转多图片上传实现方案咨询

Flutter 单图上传改造为多图上传方案

以下是改造后的完整代码,支持一次性选择多张图片并批量上传:

import 'dart:convert';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:http/http.dart' as http;

class UploadImageDemo extends StatefulWidget {
  UploadImageDemo() : super();

  final String title = "Upload Image Demo";

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

class UploadImageDemoState extends State<UploadImageDemo> {
  static final String uploadEndPoint =
      'http://localhost/flutter_test/upload_image.php';
  Future<List<File>> files;
  String status = '';
  List<String> base64Images = [];
  List<File> tmpFiles = [];
  String errMessage = 'Error Uploading Images';
  int uploadedCount = 0;

  chooseImages() {
    setState(() {
      files = ImagePicker.pickMultiImage(source: ImageSource.gallery);
    });
    setStatus('');
    uploadedCount = 0;
    base64Images.clear();
    tmpFiles.clear();
  }

  setStatus(String message) {
    setState(() {
      status = message;
    });
  }

  startUpload() {
    if (tmpFiles.isEmpty) {
      setStatus(errMessage);
      return;
    }
    setStatus('Uploading ${tmpFiles.length} images...');
    uploadedCount = 0;
    // 循环上传每张图片
    for (int i = 0; i < tmpFiles.length; i++) {
      String fileName = tmpFiles[i].path.split('/').last;
      upload(fileName, i);
    }
  }

  upload(String fileName, int index) {
    http.post(uploadEndPoint, body: {
      "image": base64Images[index],
      "name": fileName,
    }).then((result) {
      setState(() {
        uploadedCount++;
      });
      if (uploadedCount == tmpFiles.length) {
        setStatus(result.statusCode == 200 
            ? 'All ${tmpFiles.length} images uploaded successfully!' 
            : errMessage);
      } else {
        setStatus('Uploaded $uploadedCount/${tmpFiles.length} images');
      }
    }).catchError((error) {
      setStatus('Upload failed at $uploadedCount/${tmpFiles.length}: $error');
    });
  }

  Widget showImages() {
    return FutureBuilder<List<File>>(
      future: files,
      builder: (BuildContext context, AsyncSnapshot<List<File>> snapshot) {
        if (snapshot.connectionState == ConnectionState.done &&
            null != snapshot.data && snapshot.data.isNotEmpty) {
          tmpFiles = snapshot.data;
          base64Images = snapshot.data.map((file) => base64Encode(file.readAsBytesSync())).toList();
          return Expanded(
            child: GridView.builder(
              gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                crossAxisCount: 2,
                crossAxisSpacing: 10,
                mainAxisSpacing: 10,
              ),
              itemCount: snapshot.data.length,
              itemBuilder: (context, index) {
                return Image.file(
                  snapshot.data[index],
                  fit: BoxFit.cover,
                );
              },
            ),
          );
        } else if (null != snapshot.error) {
          return const Text(
            'Error Picking Images',
            textAlign: TextAlign.center,
          );
        } else {
          return const Text(
            'No Images Selected',
            textAlign: TextAlign.center,
          );
        }
      },
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Upload Multiple Images Demo"),
      ),
      body: Container(
        padding: EdgeInsets.all(30.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            OutlineButton(
              onPressed: chooseImages,
              child: Text('Choose Multiple Images'),
            ),
            SizedBox(
              height: 20.0,
            ),
            showImages(),
            SizedBox(
              height: 20.0,
            ),
            OutlineButton(
              onPressed: startUpload,
              child: Text('Upload All Images'),
            ),
            SizedBox(
              height: 20.0,
            ),
            Text(
              status,
              textAlign: TextAlign.center,
              style: TextStyle(
                color: Colors.green,
                fontWeight: FontWeight.w500,
                fontSize: 16.0,
              ),
            ),
            SizedBox(
              height: 20.0,
            ),
          ],
        ),
      ),
    );
  }
}

关键改动说明

  • 变量类型调整:将单个File相关的变量(file、tmpFile、base64Image)改为集合类型(List<File>、List<String>),用于存储多张图片的数据。
  • 图片选择方法替换:使用ImagePicker.pickMultiImage()替代pickImage(),支持一次性选择多张图片。
  • 图片展示优化:用GridView.builder替代单个Image.file,以网格形式展示选中的所有图片,更直观。
  • 批量上传逻辑:循环遍历选中的图片列表,逐个调用上传接口;新增uploadedCount变量跟踪上传进度,实时更新状态提示。
  • 状态提示优化:状态文本会显示当前上传进度(如Uploaded 2/5 images),全部完成后提示成功信息。

注意事项

  1. 确保你的后端接口upload_image.php支持接收单张图片的上传请求,如果需要批量上传可进一步修改后端逻辑,将多张图片打包发送。
  2. 若需要处理大图片,建议在上传前添加图片压缩逻辑,避免上传超时或内存占用过高。

内容的提问来源于stack exchange,提问作者YourDeveloper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 05:15:36