在 Flutter 中使用 Multi Image Picker 选择图像后如何获取图像路径?

Posted

技术标签:

【中文标题】在 Flutter 中使用 Multi Image Picker 选择图像后如何获取图像路径?【英文标题】:In Flutter How to get image path after selecting images using Multi Image Picker? 【发布时间】:2020-06-26 17:03:57 【问题描述】:

我想从选定的多个图像中获取一个图像路径,我正在使用这个link 来选择多个图像,但我有资产,我想要来自选定的多个图像的路径,因为我想上传到 API。 我在pubspec.yaml添加了这个依赖如果有什么好的方法请告诉我

multi_image_picker: ^4.6.3

这是我的文件上传类,这个 UI 看起来很像 Facebook。

import 'dart:typed_data';
import 'package:auto_size_text/auto_size_text.dart';
import 'package:flutter/material.dart';
import 'package:multi_image_picker/multi_image_picker.dart';

class UpdateStatus extends StatefulWidget 
  @override
  _UpdateStatusState createState() => _UpdateStatusState();


class _UpdateStatusState extends State<UpdateStatus> 
  List<Asset> images = List<Asset>();
  String _error = 'No Error Dectected';

  Future<ByteData> byteData;
 // List<int> imageData = byteData.buffer.asUint8List();

  @override
  void initState() 
    // TODO: implement initState
    super.initState();
  

  @override
  Widget build(BuildContext context) 
    return Scaffold(
      appBar: AppBar(
        title: Text('Create Post'),
        actions: <Widget>[
          Padding(
            padding: const EdgeInsets.all(18.0),
            child: InkWell(child: Text('POST',style: TextStyle(fontSize: 18.0),),onTap: ()
              
                print('Post this post');
              ,),
          )
        ],
      ),
      body: SingleChildScrollView(
        child: Container(
          height: MediaQuery.of(context).size.height,
          width:MediaQuery.of(context).size.width ,
          color: Colors.white,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: <Widget>[
              Container(
                height: 300.0,
                color: Colors.white,
                child: Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: TextFormField(
                    keyboardType: TextInputType.multiline,
                    maxLines: 100,
                      style: new TextStyle(
                          fontSize: 18.0,
                          color: Colors.black
                      ),
                    decoration: InputDecoration(
                      hintText: 'Enter your Post Details Here !',
                      border: InputBorder.none,
                    ),
                  ),
                ),
              ),
              Divider(
                thickness: 1.0,
              ),
              Column(
                children: <Widget>[
                  Container(
                    height: 40.0,
                    color: Colors.white70,
                    child: Padding(
                      padding:EdgeInsets.only(left: 18.0,),
                      child: InkWell(
                        child: Row(
                          children: <Widget>[
                            Icon(Icons.add_a_photo,),
                            Text("  Choose Image",style: TextStyle(fontSize: 24.0,),),
                          ],
                        ),
                        onTap: ()
                        
                          print(images.toList().toString());
                          print('choose image from local');
                        ,
                      ),
                    ),
                  ),
                  Divider(
                    thickness: 1.0,
                  ),
                  Container(
                    height: 40.0,
                    color: Colors.white70,
                    child: Padding(
                      padding:EdgeInsets.only(left: 18.0,),
                      child: InkWell(
                        child: Row(
                          children: <Widget>[
                            Icon(Icons.add_photo_alternate,),
                            Text("  Choose Video",style: TextStyle(fontSize: 24.0,),),
                          ],
                        ),
                        onTap: ()
                        
                          print('choose video from local');
                        ,
                      ),
                    ),
                  ),
                ],
              ),
              Divider(
                thickness: 1.0,
              ),
         Container(
           height: 200,
              child: Column(
                children: <Widget>[
                  Center(child: Text('Error: $_error')),
                  RaisedButton(
                    child: Text("Pick images"),
                    onPressed: loadAssets,
                  ),
                  Expanded(
                    child: buildGridView(),
                  )
                ],
              ),
         ),
         /*
          Column(
            children: <Widget>[
              Center(child: Text('Error: $_error')),
              RaisedButton(
                child: Text("Pick images"),
                onPressed: loadAssets,
              ),
              Expanded(
                child: buildGridView(),
              )
            ],
          ),

              */
            ],
          ),
        ),
      ),
    );
  

  Future<void> loadAssets() async 

    List<Asset> resultList = List<Asset>();
    String error = 'No Error Dectected';

    ByteData byteData;


    try 
      resultList = await MultiImagePicker.pickImages(
        maxImages: 300,
        enableCamera: true,
        selectedAssets: images,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Ilma",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );

     on Exception catch (e) 
      error = e.toString();
    

    // If the widget was removed from the tree while the asynchronous platform
    // message was in flight, we want to discard the reply rather than calling
    // setState to update our non-existent appearance.
    if (!mounted) return;

    setState(() 
      images = resultList;
      _error = error;
      print('000000000000000000000');
      print('000000000000000000000');
      print(images);
      print('000000000000000000000');
      print('000000000000000000000');
    );



  

  Widget buildGridView() 
    return GridView.count(
      crossAxisCount: 3,
      children: List.generate(images.length, (index) 
        Asset asset = images[index];

        byteData=asset.getByteData();

        print('0000');
        print(byteData);
        print('0000');



        return AssetThumb(
          asset: asset,
          width: 300,
          height: 300,
        );
      ),
    );
  


【问题讨论】:

您如何上传您的数据?使用http 包?或dio?还是别的什么? 我正在使用http包,谢谢,希望你能帮助我 所以你有原始字节要上传 (asset.getByteData()),不是吗?那有什么问题呢? 如果我打印 byteData print(byteData); 我得到了这个输出 Instance of 'Future&lt;ByteData&gt;' 你要查看我发布的链接 【参考方案1】:
Padding(
            padding: const EdgeInsets.all(18.0),
            child: InkWell(
              child: Text(
                'POST',
                style: TextStyle(fontSize: 18.0),
              ),
              onTap: () async 

 List<MultipartFile> multipart = List<MultipartFile>();

                for (int i = 0; i < images.length; i++) 
                  var path = await FlutterAbsolutePath.getAbsolutePath(images[i].identifier);

                   

              ,
            ),
          )

【讨论】:

【参考方案2】:

我正在使用下面的代码通过 file_picker: ^2.0.7 库来选择多个图像。 长按选择多张图像。选择图像后,您可以使用 f arr 来显示图像。

List<File> f = List();

 RaisedButton(
            child: Text("Pick Image"),
            onPressed: () async 
              FilePickerResult result = await FilePicker.platform.pickFiles(
                allowMultiple: true,
                type: FileType.custom,
                allowedExtensions: ['jpg', 'png', 'jpeg'],
              );
              if (result != null) 
                f = result.paths.map((path) => File(path)).toList();
                setState(() );
                print(f);
              
            ,
          ),

用于图像上传和普通数据的示例 API 调用。图片上传栏应为 arr ( photo[] )。

 List<MultipartFile> newList = new List<MultipartFile>();


Future<String> ImageUpload() async 

var request = http.MultipartRequest('POST', url);
 request.headers["Authorization"] = pref.getString("token");
    request.headers["Accept"] = "application/json";
   //Image Data
  for (int i = 0; i < f.length; i++) 
      newList.add(await http.MultipartFile.fromPath('photo[]', f[i].path));
    
    request.files.addAll(newList);
    
    Map<String, dynamic> data = Map<String, String>();
    //normal data
    data["user_id"] = user_id;
    data["project_id"] = pro_id;
    
    request.fields.addAll(data);
    var res = await request.send();
    
    if (res.statusCode == 200) 
      debugPrint("Status$res");
      else 
      debugPrint("status code$res");
      
      
    
    
Try This You can select and upload multiple images easily. Thank you.

【讨论】:

【参考方案3】:

使用 multi_image_picker 4.7.14 库选择多个图像。使用下面的代码,您可以将选定的资产图像作为文件发送。 `

//Inside Widget Builder
FlatButton(
            child: Image.asset(
              "assets/images/camera.png",
              color: Colors.grey,
            ),
            onPressed: loadAssets,
          ),
          
    SizedBox(
                  // height: SizeConfig.safeBlockHorizontal * 10,
                  height: MediaQuery.of(context).size.height / 2,
                  child: Column(
                    children: <Widget>[
                      Expanded(
                        child: buildGridView(),
                      ),
                    ],
                  ),
                )

List<File> fileImageArray = [];
  List<String> f = List();
  List<Asset> resultList = List<Asset>();
  List<Asset> images = List<Asset>();
  
  Future<void> loadAssets() async 
    try 
      resultList = await MultiImagePicker.pickImages(
        maxImages: 4,
        enableCamera: true,
        selectedAssets: images,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Example App",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );
     on Exception catch (e) 
      error = e.toString();
    

    if (!mounted) return;

    for (int i = 0; i < resultList.length; i++) 
      var path =
          await FlutterAbsolutePath.getAbsolutePath(resultList[i].identifier);
      print(path);
      f.add(File(path));
    

    setState(() 
      images = resultList;
    );

    // return fileImageArray;
  

//image PreView
  Widget buildGridView() 
    return GridView.count(
      crossAxisCount: 4,
      children: List.generate(images.length, (index) 
        Asset asset = images[index];
        return AssetThumb(
          asset: asset,
          width: 50,
          height: 50,
        );
      ),
    );
  

API调用:上传图片的地方使用多部分文件

List<MultipartFile> newList = new List<MultipartFile>();
    
  Future<String> multiImagePostAPI() async 
    var request = http.MultipartRequest('POST', url);
    request.headers["Authorization"] = pref.getString("token");
    request.headers["Accept"] = "application/json";
    
     for (int i = 0; i < f.length; i++) 
      newList.add(await http.MultipartFile.fromPath('photo[]', f[i].path));
    
    request.files.addAll(newList);
     Map<String, dynamic> data = Map<String, String>();
      data["user_id"] = user_id;
      data["project_id"] = pro_id;
      data["title"] = titleController.text;

      request.fields.addAll(data);

      var res = await request.send();
     
     if (res.statusCode == 200) 
      debugPrint("Status$res");
     else 
      debugPrint("status : $res");
      
      
     
     

【讨论】:

做了这个,但我收到了一个错误,上面写着E/flutter (16058): [ERROR:flutter/lib/ui/ui_dart_state.cc(199)] Unhandled Exception: Bad state: Can't finalize a finalized MultipartFile.,我完全按照你所做的,请帮助 请检查库版本。因为这个版本太旧了,可能是版本问题。【参考方案4】:

您还可以使用 file_picker: ^1.5.0+2 库选择多个图像,并轻松获取所选图像的路径

Future<int> getFilePath() async 
try 
  files = await FilePicker.getMultiFile();
  if (files == '') 
    return 0;
  
  else
  
    setState(() 
      this._filePath = files;
      return 1;
    );
  

 on PlatformException catch (e) 
  print("Error while picking the file: " + e.toString());

像这样使用 ListView Builder 显示选定的图像

               ListView.builder(
              scrollDirection: Axis.horizontal,
              itemCount: _filePath.length,
              itemBuilder: (context,c)
              

                return Card(
                  child: Image.file(_filePath[c],
                    fit: BoxFit.fill,
                    width: 400,
                    height: 400,

                  ),
                );
              
          ),

【讨论】:

以上是关于在 Flutter 中使用 Multi Image Picker 选择图像后如何获取图像路径?的主要内容,如果未能解决你的问题,请参考以下文章

在我在 Flutter 中打开 Google Photos 之前,Multi Image Picker 无法找到我的图片

Flutter 无法上传从 multi_image_picker 获取的多张图片

在flutter multi_image_picker 4.7.14中访问相机后,iOS 14绿点通知灯始终可见

“multi_image_picker”颤动的问题

如何在 Flutter 中获取 Asset 对象的路径?

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