如何在 Flutter Firestore 提供程序中显示数据

Posted

技术标签:

【中文标题】如何在 Flutter Firestore 提供程序中显示数据【英文标题】:how to display data in flutter firestore provider 【发布时间】:2020-06-09 04:17:46 【问题描述】:

我想在 Flutter 中使用提供程序显示来自 Firestore 的数据。我被卡住了,请帮忙。以下是我的代码

//产品展示页面

   import 'package:flutter/material.dart';
    import 'package:provider/provider.dart';
    import 'package:shopping/pages/product_details.dart';
    import 'package:shopping/provider/app_provider.dart';
    class Product extends StatefulWidget 
      @override
      _ProductState createState() => _ProductState();
    

    class _ProductState extends State<Product> 


      @override
      Widget build(BuildContext context) 
      final product = Provider.of<AppProvider>(context);


         return GridView.builder(
           itemCount: productList.length,
           gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
         itemBuilder: (BuildContext context, int index)

         return Padding(
        padding:const EdgeInsets.all(4.0),
         child:SingleProd(
            //where i want to get the product details 
             prodName: product.featuredProducts[index].name.toString(),

           ),
           );
         
          );
      
    
    class SingleProd extends StatelessWidget 
      final prodName;
      final prodPicture;
      final prodOldPrice;
      final prodPrice;

      SingleProd(this.prodName, this.prodPicture,this.prodOldPrice,this.prodPrice);
      @override
      Widget build(BuildContext context) 
        return Card(
    child: Hero(tag: new Text("hero 1"),
     child:
     Material( child: InkWell(
    onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
      //here we are passing the value of the products to Product detail page
    productDetailName:prodName,

    )
    )
    ),
     child:GridTile(
    footer: Container(
      color: Colors.white,
      child: new Row(
        children: <Widget>[
          new Expanded(
            child: new Text(prodName, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
          ),
          new Text(
            "\$$prodPrice", style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
        ],
      )
    ),
     child: Image.asset(prodPicture, 
       fit: BoxFit.cover,),
     ),
     ),
    ),
    ),
        );
      



    

//产品类

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/foundation.dart';
class Product
  static const ID = "id";
  static const CATEGORY = "category";
  static const NAME = "name";
  static const PRICE = "price";
  static const BRAND = "brand";
  static const COLORS = "colors";
  static const QUANTITY = "quantity";
  static const SIZES = "sizes";
  static const SALE = "sale";
  static const FEATURED = "featured";
  static const PICTURE = "picture";


  String _id;
  String _name;
  String _brand;
  String _category;
  String _picture;
  double _price;
  int _quantity;
  List _colors;
  List _sizes;
  bool _onSale;
  bool _featured;

//  getters
  String get name => _name;
  String get id => _id;
  String get category => _category;
  String get brand => _brand;
  String get picture => _picture;
  double get price => _price;
  int get quantity => _quantity;
  List get colors => _colors;
  List get sizes => _sizes;
  bool get onSale => _onSale;
  bool get featured => _featured;

//  named constructure
  Product.fromSnapshot(DocumentSnapshot snapshot)
    Map data = snapshot.data;
    _name = data[NAME];
    _id = data[ID];
    _category = data[CATEGORY];
    _brand = data[BRAND];
    _price = data[PRICE];
      _quantity = data[QUANTITY];
    _colors = data[COLORS];
    _onSale = data[SALE];
    _featured = data[FEATURED];
    _picture = data[PICTURE];
  

 

//产品的供应商页面

     import 'package:flutter/material.dart';
    import 'package:shopping/db/product.dart';
    import 'package:shopping/models/product.dart';

     class AppProvider with ChangeNotifier 
       List<Product>_fearturedProducts=[];
       //method
       void _getFeaturedProducts()async

        _fearturedProducts=await _productService.getFeaturedProducts();
        notifyListeners();
       
     

//连接到 Firestore 以收集数据

    import 'package:cloud_firestore/cloud_firestore.dart';
    import 'package:shopping/models/product.dart';

    class ProductService
        Firestore _firestore=Firestore.instance;
      String collection="Products";

      Future<List<Product>>getFeaturedProducts()

     _firestore.collection(collection).where('featured', isEqualTo:true).getDocuments()
     .then((snap)

      List<Product>featuredProducts=[];
       snap.documents.map((snapshot)=> featuredProducts.add(Product.fromSnapshot(snapshot)));
       return featuredProducts;
     ); 

    

    

【问题讨论】:

【参考方案1】:

你永远不会从你的 AppProvider 类中调用 _getFeaturedProducts()。所以_fearturedProducts 将永远为空

【讨论】:

如何调用 _getFeaturedProducts() 请帮忙 这是你自己的代码,你需要从firebase获取结果才能构建网格【参考方案2】:

在 AppProvider 类中,您正在调用未定义名称的方法:

_productService.getFeaturedProducts()

每个 IDE 都应该向您显示此错误。在我的 android Studio 中,它看起来像这样:

【讨论】:

【参考方案3】:

伙计们,我已经设法解决了这个问题。答案如下 //产品页面

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:shopping/pages/product_details.dart';
import 'package:shopping/provider/app_provider.dart';
import 'package:shopping/models/product.dart';
class Products extends StatefulWidget 
  @override
ProductsState createState() => ProductsState();


class ProductsState extends State<Products> 
  List<Product> products;
  @override
  Widget build(BuildContext context) 

    final productProvider = Provider.of<CRUDModel>(context);
    return  StreamBuilder<QuerySnapshot>(
            stream: productProvider.fetchProductsAsStream(),
            builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) 
              if (snapshot.hasData) 
                products = snapshot.data.documents
                    .map((doc) => Product.fromMap(doc.data, doc.documentID))
                    .toList();

     return GridView.builder(
       itemCount: products.length,
       gridDelegate:new SliverGridDelegateWithFixedCrossAxisCount(crossAxisCount:2),
     itemBuilder: (BuildContext context,  index)

     return Padding(
    padding:const EdgeInsets.all(4.0),
     child:SingleProd(
         product:products[index]
        // prodPicture: productList[index]['picture'],
         //prodOldPrice: productList[index]['oldPrice'],
         //prodPrice: productList[index]['price'],
       ),
       );
     
      );
      
     else 
                return Text('fetching');
              
  

  );

  



class SingleProd extends StatelessWidget 
 //final prodName;
  //final prodPicture;
  //final prodOldPrice;
  //final prodPrice;
    final Product product;

  SingleProd( @required this.product);


  //SingleProd(product.picture);
  @override
  Widget build(BuildContext context) 
    return Card(
child: Hero(tag: product.id,
 child:
 Material( child: InkWell(
onTap: ()=>Navigator.of(context).push(new MaterialPageRoute(builder: (context)=>ProductDetails(
  //here we are passing the value of the products to Product detail page
productDetailName:product.name,
productDetailNewPrice:product.price,
productDetailPicture:product.picture,
//productDetailOldPrice:prodOldPrice,
//productDetailNewPrice:prodPrice,
//productDetailPicture: prodPicture,
)
)
),
 child:GridTile(
footer: Container(
  color: Colors.white,
  child: new Row(
    children: <Widget>[
      new Expanded(
        child: new Text(product.name, style: TextStyle(fontWeight: FontWeight.bold, fontSize:16.0),),
      ),
      new Text(
        '$product.price \$', style: TextStyle(color: Colors.red, fontWeight: FontWeight.bold),)
    ],
  )
),
 child: Image.asset('assets/$product.picture.jpg',

   fit: BoxFit.cover,),
 ),
 ),
),
),

    );
  
   

//产品类

import 'package:cloud_firestore/cloud_firestore.dart';

import 'dart:ui';

class Product 
  String id;
  String name;
  String brand;
  String category;
  String picture;
  double price;
  int quantity;
  List colors;
  List sizes;
  bool sale;
  bool featured;

  Product(
    this.id, this.name, this.brand, 
    this.category, this.picture,this.price,
     this.quantity,this.colors,this.sizes,this.sale,this.featured
    );

  Product.fromMap(Map snapshot,String id) :
        id = id ?? '',
        name= snapshot['name'] ?? '',
        brand = snapshot['brand'] ?? '',
        category = snapshot['category'] ?? '',
        picture= snapshot['picture'] ?? '',
        price= snapshot['price'] ?? '',
        quantity= snapshot['quantity'] ?? '',
        colors= snapshot['colors'] ?? '',
        sizes= snapshot['sizes'] ?? '',
        sale= snapshot['sale'] ?? '',
        featured= snapshot['featured'] ?? '';



  toJson() 
    return 
      "name": name,
      "brand": brand,
      "category": category,
      "picture": picture,
      "price": price,
      "quantity": quantity,
      "colors": colors,
      "sizes": sizes,
      "sale": sale,
      "featured": brand,
    ;
  

//产品的提供者类

 import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:shopping/db/Api.dart';
import 'package:shopping/models/product.dart';


 class CRUDModel extends ChangeNotifier 

  //Api _api = locator<Api>();
String path="Products";
  Api _api= Api();

  List<Product> products;


  Future<List<Product>> fetchProducts() async 
    var result = await _api.getDataCollection();
    products = result.documents
        .map((doc) => Product.fromMap(doc.data, doc.documentID))
        .toList();
        notifyListeners();
    return products;
  

  Stream<QuerySnapshot> fetchProductsAsStream() 
    notifyListeners();
    return _api.streamDataCollection();
  

  Future<Product> getProductById(String id) async 
    var doc = await _api.getDocumentById(id);
    notifyListeners();
    return  Product.fromMap(doc.data, doc.documentID) ;
  


//连接到firestore

import 'package:cloud_firestore/cloud_firestore.dart';

class Api
  final Firestore _db = Firestore.instance;
  String ref="Products";
 //CollectionReference ref;

  /*Api(this.path  ) 
    ref = _db.collection(path);
  */

  Future<QuerySnapshot> getDataCollection() 
    //return ref.getDocuments() ;

   return  _db.collection(ref).where('featured', isEqualTo:true).getDocuments();

  
  Stream<QuerySnapshot> streamDataCollection() 
   // return ref.snapshots() ;
  //return _db.snapshots(ref).getDocuments();
  return _db.collection(ref).snapshots();
  
  Future<DocumentSnapshot> getDocumentById(String id) 
   // return ref.document(id).get();
   return _db.document(id).get();
  
  Future<void> removeDocument(String id)
    //return ref.document(id).delete();
    return _db.document(id).delete();
  
  Future<DocumentReference> addDocument(Map data) 
   // return ref.add(data);
   return _db.collection(ref).add(data);
  
  Future<void> updateDocument(Map data , String id) 
    //return ref.document(id).updateData(data) ;
    return _db.document(ref).updateData(data);
  



//我展示产品的主页

import 'package:flutter/material.dart';
import 'package:carousel_pro/carousel_pro.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:shopping/commons/common.dart';
import 'package:provider/provider.dart';
import 'package:shopping/provider/app_provider.dart';
import '../provider/user_provider.dart';

//My packages imports
import 'package:shopping/componets/horizontal_listview.dart';
import 'package:shopping/componets/product.dart';
import 'package:shopping/pages/cart.dart';
import 'package:shopping/pages/login.dart';

class HomePage extends StatefulWidget 
   // List<Product> products;

  @override
  _HomePageState createState() => _HomePageState();


class _HomePageState extends State<HomePage> 
  TextEditingController _searchController = new TextEditingController();

  //final FirebaseAuth _firebaseAuth=FirebaseAuth.instance;

  @override
  Widget build(BuildContext context) 
   final user = Provider.of<UserProvider>(context);
   final productProvider=Provider.of<CRUDModel>(context);
    Widget image_carousel = new Container(
      height: 200.0,
      child: new Carousel(
        boxFit: BoxFit.cover,
        images: [
          AssetImage('images/c1.jpg'),
          AssetImage('images/m1.jpeg'),
          AssetImage('images/m2.jpg'),
          AssetImage('images/w1.jpeg'),
          AssetImage('images/w3.jpeg'),
          AssetImage('images/w4.jpeg'),
        ],
        autoplay:true,
        animationCurve: Curves.fastOutSlowIn,
        animationDuration: Duration(milliseconds:1000 ),
        dotSize: 4.0,
        indicatorBgPadding: 8.0,
        dotBgColor: Colors.transparent,
      ),
    );
    return Scaffold(
      appBar: new AppBar(
        iconTheme: IconThemeData(color: blue),
        elevation: 0.1,
        backgroundColor: white,
        title: Material(
          borderRadius: BorderRadius.circular(20),
          color: Colors.grey[50],
          elevation: 0.0,
          child: TextFormField(
              controller: _searchController,
              decoration: InputDecoration(
                hintText: "Search",
                border: InputBorder.none,
              ),
              validator: (value) 
                if (value.isEmpty) 
                  return "The Search field  cannot be empty";
                
                return null;
              ),
        ),
        actions: <Widget>[
          new IconButton(
            icon: Icon(
              Icons.search,
              color: blue,
            ),
            onPressed: () ,
          ),
          new IconButton(
              icon: Icon(
                Icons.shopping_cart,
                color: blue,
              ),
              onPressed: () 
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => new Cart()));
              ),
        ],
      ),
      drawer: new Drawer(
        child: new ListView(
          children: <Widget>[
            //drawer header
            new UserAccountsDrawerHeader(
              accountName: Text("Afolabi"),
              accountEmail: Text("mtreal62@gmail.com"),
              currentAccountPicture: GestureDetector(
                child: new CircleAvatar(
                  backgroundColor: Colors.grey,
                  child: Icon(
                    Icons.person,
                    color: Colors.white,
                  ),
                ),
              ),
              decoration: BoxDecoration(
                color: blue,
              ),
            ),
            //body
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("Home Page"),
                leading: Icon(
                  Icons.home,
                  color: blue,
                ),
              ),
            ),
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("My Account"),
                leading: Icon(
                  Icons.person,
                  color: blue,
                ),
              ),
            ),
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("My Orders"),
                leading: Icon(
                  Icons.shopping_basket,
                  color: blue,
                ),
              ),
            ),
            InkWell(
              onTap: () 
                Navigator.push(context,
                    MaterialPageRoute(builder: (context) => new Cart()));
              ,
              child: ListTile(
                title: Text("Shopping Cart"),
                leading: Icon(
                  Icons.shopping_cart,
                  color: blue,
                ),
              ),
            ),
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("Favourites"),
                leading: Icon(
                  Icons.favorite,
                  color: blue,
                ),
              ),
            ),
            Divider(),
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("Settings"),
                leading: Icon(
                  Icons.settings,
                ),
              ),
            ),
            InkWell(
              onTap: () ,
              child: ListTile(
                title: Text("About"),
                leading: Icon(
                  Icons.help,
                ),
              ),
            ),

            InkWell(
              onTap: () 
               user.signOut();
        // changeScreenReplacement(context, Login());
              ,
              child: ListTile(
                title: Text("Log Out"),
                leading: Icon(
                  Icons.transit_enterexit,
                ),
              ),
            ),
          ],
        ),
      ),
      body: new Column(
        children: <Widget>[
          //Image Carousel for the home Page Banner
          image_carousel,
          //padding widget after carousel
          new Padding(
            padding: const EdgeInsets.all(8.0),
            child: Container(
              alignment: Alignment.centerLeft,
              child: new Text("Categories"),
            ),
          ),
          //Horizontal layout start from here
          HorizontalList(),
          //End of the horizontal layout

          //padding widget for Recent products categories
          new Padding(
            padding: const EdgeInsets.all(8.0),
            child: Container(
              alignment: Alignment.centerLeft,
              child: new Text("Recent Products"),
            ),
          ),
              // Text(appProvider.featuredProducts.length.toString(),
                 //style: TextStyle(color: Colors.black),),

          Flexible(
            child: Products(),
          ),
          //Horizontal layout start from here
        ],
      ),
    );
  


Future _signOut() async 
  try 
    await FirebaseAuth.instance.signOut();
   catch (e) 
    print(e); // TODO: show dialog with error
  

【讨论】:

以上是关于如何在 Flutter Firestore 提供程序中显示数据的主要内容,如果未能解决你的问题,请参考以下文章

如何使用flutter更新firestore中所有文档的单个字段?

Flutter - 使用提供者和 Firestore 返回空列表

Flutter - 使用提供程序包侦听 Firebase 用户的用户配置文件(Firestore)中的数据更改

每次加载应用程序时,如何防止 Firestore 加载整个用户数据

如何在flutter中从云Firestore中获取数据?

如何在flutter中获取firestore文档的documentid?