如何在 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)中的数据更改