首页 > 解决方案 > 将资产列表上传到 Firebase 存储并获取字符串列表 Flutter

问题描述

我有个问题。

所以我试图将多张图片上传到 Firebase 存储中,这些图片通过MultiImage选择器进入手机内存,该选择器仅将数据保存到 List < Asset > 中,这里的代码:

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:multi_image_picker2/multi_image_picker2.dart';
import 'package:provider/provider.dart';

import '../widgets/bottom_navigation_bar.dart';
import '../providers/selling.dart';

//Property Features Screens
import '../screens/land_lot_size_features.dart';
import '../screens/condo_property_details_features.dart';
import '../screens/townhose_property_detais_features.dart';
import '../screens/home_property_details_features.dart';

import '../screens/selling_bathrooms.dart';

//Next Page Pricing
import '../screens/pricing_property.dart';

class MultipleImageDemo extends StatefulWidget {
  static const routeName = '/multi-picker';

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

class _MultipleImageDemoState extends State<MultipleImageDemo> {
  List<Asset> images = <Asset>[];
  double screenWidth = 0;
  bool isLoading = false;

  @override
  void initState() {
    setState(() {
      isLoading = true;
    });
    images = Provider.of<Selling>(context, listen: false).images;
    setState(() {
      isLoading = true;
    });
    super.initState();
  }

  Future<void> loadAssets() async {
    List<Asset> resultList = <Asset>[];

    try {
      resultList = await MultiImagePicker.pickImages(
        maxImages: 12,
        enableCamera: true,
        selectedAssets: images,
        cupertinoOptions: CupertinoOptions(takePhotoIcon: "chat"),
        materialOptions: MaterialOptions(
          actionBarColor: "#abcdef",
          actionBarTitle: "Roof Deck",
          allViewTitle: "All Photos",
          useDetailsView: false,
          selectCircleStrokeColor: "#000000",
        ),
      );
    } on Exception catch (e) {
      //String error = e.toString();
      print(e);
    }

    if (!mounted) return;

    setState(() {
      images = resultList;
    });
  }

  deleteImage(index) {
    images.removeAt(index);
    setState(() {});
  }

  @override
  Widget build(BuildContext context) {
    final topData = Provider.of<Selling>(context);
    final typeOfProperty = topData.menu;
    screenWidth = MediaQuery.of(context).size.width;

    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            // SizedBox(
            //   height: 1,
            // ),
            // Positioned(
            //   top: 0,
            //   left: 0,
            //   right: 0,
            //   child: Container(
            //     width: screenWidth,
            //     padding: const EdgeInsets.all(15),
            //     margin: const EdgeInsets.all(15),
            //     child: LinearPercentIndicator(
            //       width: screenWidth / 1.2,
            //       lineHeight: 8.0,
            //       percent: 0.50,
            //       progressColor: Colors.deepPurple[900],
            //     ),
            //   ),
            // ),
            Container(
              // width: screenWidth,
              // padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
              // margin: const EdgeInsets.symmetric(horizontal: 15, vertical: 5),
              child: CustomScrollView(
                slivers: [
                  SliverToBoxAdapter(
                    child: Container(
                      // padding: const EdgeInsets.only(
                      //   top: 5,
                      //   left: 15,
                      //   right: 15,
                      // ),
                      // margin: const EdgeInsets.only(
                      //   top: 5,
                      //   left: 15,
                      //   right: 15,
                      // ),
                      child: Column(
                        children: [
                          Center(
                            child: Text(
                              'Photos',
                              style: TextStyle(fontSize: 25),
                            ),
                          ),
                          Divider(
                            color: Colors.grey,
                            thickness: 2.00,
                          ),
                          SizedBox(
                            height: 5,
                          ),
                        ],
                      ),
                    ),
                  ),
                  // SliverToBoxAdapter(
                  //   child: Padding(
                  //     padding: const EdgeInsets.only(
                  //         left: 15.0, right: 15.0, bottom: 5.0),
                  //     child: Text(
                  //       'Homes are 30% more likely to sell with high quality photos.',
                  //       style: TextStyle(
                  //         color: Colors.grey,
                  //         fontSize: 18.00,
                  //       ),
                  //     ),
                  //   ),
                  // ),
                  // SliverToBoxAdapter(
                  //   child: Padding(
                  //     padding: const EdgeInsets.only(
                  //         left: 15.0, right: 15.0, bottom: 20.0),
                  //     child: Text(
                  //       'You can only upload 12 pictures, if you need to remove a picture just tap on it.',
                  //       style: TextStyle(
                  //         color: Colors.grey,
                  //         fontSize: 18.00,
                  //       ),
                  //     ),
                  //   ),
                  // ),
                  SliverPadding(
                    padding: const EdgeInsets.symmetric(
                      horizontal: 15,
                    ),
                    sliver: SliverGrid(
                      delegate: SliverChildBuilderDelegate(
                        (BuildContext context, int index) {
                          return index == images.length
                              ? Center(
                                  child: DecoratedBox(
                                    decoration: BoxDecoration(
                                      color: Colors.grey,
                                      borderRadius: BorderRadius.circular(5),
                                      border: Border.all(
                                          color: Colors.grey, width: 1.0),
                                    ),
                                    child: Container(
                                      margin: const EdgeInsets.all(16.0),
                                      padding: const EdgeInsets.all(8.0),
                                      height: 100,
                                      width: 100,
                                      child: IconButton(
                                        icon: Icon(
                                          Icons.add, //add_a_photo,
                                          size: 50.00,
                                          color: Colors.white,
                                        ),
                                        onPressed: () {
                                          if (images.length < 12) {
                                            loadAssets();
                                          } else {
                                            showDialog(
                                              context: context,
                                              builder: (ctx) => AlertDialog(
                                                title: Text(
                                                    'Max Number of Pictures'),
                                                content: Text(
                                                    'You reached the maximum number of pictures that can be uploaded (12 pictures)'),
                                                actions: [
                                                  TextButton(
                                                    child: Text('Okay'),
                                                    onPressed: () {
                                                      Navigator.of(ctx).pop();
                                                    },
                                                  ),
                                                ],
                                              ),
                                            );
                                          }
                                        },
                                      ),
                                    ),
                                  ),
                                )
                              : GestureDetector(
                                  onTap: () {
                                    deleteImage(index);
                                  },
                                  child: Container(
                                    margin: const EdgeInsets.all(3),
                                    decoration: BoxDecoration(
                                      border: Border.all(
                                          color: Colors.grey, width: 1.0),
                                      borderRadius: BorderRadius.all(
                                        Radius.circular(5.0),
                                      ),
                                    ),
                                    child: ClipRRect(
                                      borderRadius: BorderRadius.circular(4.0),
                                      child: AssetThumb(
                                        asset: images[index],
                                        width: 300,
                                        height: 300,
                                      ),
                                    ),
                                  ),
                                );
                        },
                        childCount: images.length + 1,
                      ),
                      gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                        crossAxisCount: 3,
                      ),
                    ),
                  ),
                ],
              ),
            ),
            Positioned(
              bottom: 0,
              left: 0,
              right: 0,
              child: Container(
                padding: const EdgeInsets.symmetric(
                  horizontal: 15,
                ),
                color: Colors.white,
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    TextButton(
                      child: Text(
                        'Previous',
                        style: TextStyle(fontSize: 22),
                      ),
                      onPressed: () {
                        switch (typeOfProperty) {
                          case 0:
                            {
                              Navigator.pushNamed(
                                  context, PropertyBathrooms.routeName);
                            }
                            break;
                          case 1:
                            {
                              Navigator.push(
                                context,
                                PageRouteBuilder(
                                    transitionDuration: Duration(seconds: 0),
                                    pageBuilder: (_, __, ___) =>
                                        LandSizeFeatures()),
                              );
                            }
                            break;
                          case 2:
                            {
                              Navigator.push(
                                context,
                                PageRouteBuilder(
                                    transitionDuration: Duration(seconds: 0),
                                    pageBuilder: (_, __, ___) =>
                                        TownhousePropertyDetails()),
                              );
                            }
                            break;
                          case 3:
                            {
                              Navigator.push(
                                context,
                                PageRouteBuilder(
                                    transitionDuration: Duration(seconds: 0),
                                    pageBuilder: (_, __, ___) =>
                                        CondoPropertyDetails()),
                              );
                            }
                            break;
                          case 4:
                            {
                              Navigator.push(
                                context,
                                PageRouteBuilder(
                                    transitionDuration: Duration(seconds: 0),
                                    pageBuilder: (_, __, ___) =>
                                        HomePropertyDetails()),
                              );
                            }
                            break;
                        }
                        // Navigator.pushNamed(
                        //     context, PropertyBathrooms.routeName);
                      },
                    ),
                    TextButton(
                      child: Text(
                        'Next',
                        style: TextStyle(fontSize: 22),
                      ),
                      onPressed: () {
                        Provider.of<Selling>(context, listen: false)
                            .getImages(images);
                        Navigator.push(
                          context,
                          PageRouteBuilder(
                              transitionDuration: Duration(seconds: 0),
                              pageBuilder: (_, __, ___) => PricingProperty()),
                        );
                        //Navigator.pushNamed(context, PropertySize.routeName);
                      },
                    ),
                  ],
                ),
              ),
            ),
          ],
        ),
      ),
      bottomNavigationBar: BottomNavBar(2),
    );
  }
}

一旦我们移动到不同的屏幕,我将该列表保存到 Provider 以使其在任何地方可用:

//***Property Images***/

  List<Asset> _images = <Asset>[];

  //Images Getter

  List<Asset> get images {
    return _images;
  }

  //Filling the Data Function

  void getImages(List<Asset> images) {
    _images = images;
    notifyListeners();
  }

  //*** END OF IMAGES ***//

上面的代码是我在图像提供程序中填充图像的方式。

现在所有这些都有效,但问题是现在我希望将该列表中的所有图像上传到 Firebase 存储并返回带有图片查看 URL (DownloadURL) 的字符串列表。

我可以通过在 1 by 1 的情况下执行此操作并发送文件而不是像以下代码一样的资产列表来做到这一点:

final ref = FirebaseStorage.instance
                .ref()
                .child('user_images')
                .child(authResult.user.uid + '.jpg');

            await ref.putFile(image);

            final url = await ref.getDownloadURL();

但是有没有办法一次完成所有这些操作,而不是一个一个地完成并检索下载 URL 的字符串列表?

我的最终目标是能够将这些图像存储在 Firebase 存储中,并将这些图像的 url 数组保存到 Firestore。

在我的简历中,我的问题是我没有上传文件或文件列表,而是上传资产列表,它是一个列表而不是单个列表。

谢谢你和亲切的问候。

标签: firebaseflutterfirebase-storageassets

解决方案


如果有人来这里寻求答案,我找到了:

  1. 首先,我将 List < File > 添加到我的 Multi Image Picker 并添加了此代码(resultList 是资产数组)。

我添加包flutter_absolute_path: ^1.0.6并得到以下代码:

resultList.forEach((imageAsset) async {
      final filePath =
          await FlutterAbsolutePath.getAbsolutePath(imageAsset.identifier);

      File tempFile = File(filePath);

      if (tempFile.existsSync()) {
        fileImageArray.add(tempFile);
      }
    });

有了它,我将文件数组保存到我的 Provider 中。然后我创建了一个函数来上传到 Firebase 存储:

Future<void> uploadImages(String id) async {
    int i = 0;
    for (File imageFile in imageFiles) {
      try {
        var ref = FirebaseStorage.instance
            .ref()
            .child('ListingImages')
            .child(id)
            .child(i.toString() + '.jpg');

        await ref.putFile(imageFile);

        var url = await ref.getDownloadURL();

        _imagesUrl.add(url);

        i++;
      } catch (err) {
        print(err);
      }
    }
    notifyListeners();
    print(_imagesUrl);
  }

允许我遍历每个上传的文件并将下载 URL 保存在字符串数组中。

希望这对你有帮助,伙计们。


推荐阅读