firebase - 自动从firestore获取数据后如何启动状态
问题描述
我是颤振的初学者,我在我的应用程序的历史页面上工作,我想做的是从 Firestore 获取数据,然后处理该数据并将其存储到一个列表中,这样我就可以在 dashbord 小部件中构建我的历史项目,问题是除非我手动刷新状态,否则项目不会出现,在我的情况下,我使用这个过滤器图标,获取我数据的函数是 getVente(),我在 initState() 中调用它,我希望这个函数在我加载页面的那一刻执行,所以项目也是如此,而不是手动执行。这是发生了什么图片gif
这是代码
import 'package:flutter/material.dart';
import 'package:rflutter_alert/rflutter_alert.dart';
import 'package:chips_choice/chips_choice.dart';
import 'package:stocknsell/Components/DownSelect.dart';
import 'package:stocknsell/Components/DownSelect2.dart';
import 'package:date_range_picker/date_range_picker.dart' as DateRagePicker;
import 'package:stocknsell/Components/historyitem.dart';
final Color backgroundColor = Color(0xFF4A4A58);
class HistoriquePage extends StatefulWidget {
static String id = "/history";
@override
_HistoriquePageState createState() => _HistoriquePageState();
}
class _HistoriquePageState extends State<HistoriquePage>
with SingleTickerProviderStateMixin {
bool isCollapsed = true;
double screenWidth, screenHeight;
final Duration duration = const Duration(milliseconds: 300);
AnimationController _controller;
Animation<double> _scaleAnimation;
Animation<double> _menuScaleAnimation;
Animation<Offset> _slideAnimation;
Vente vente;
List<Vente> list = List();
List<Produit> produits = List();
Produit produit = Produit();
@override
void initState() {
getVente();
_controller = AnimationController(vsync: this, duration: duration);
_scaleAnimation = Tween<double>(begin: 1, end: 0.8).animate(_controller);
_menuScaleAnimation =
Tween<double>(begin: 0.5, end: 1).animate(_controller);
_slideAnimation = Tween<Offset>(begin: Offset(-1, 0), end: Offset(0, 0))
.animate(_controller);
super.initState();
}
void getVente() async {
bool trouve = false;
await for (var snapshots
in FirebaseFirestore.instance.collection('vente').snapshots()) {
for (var ventes in snapshots.docs) {
if ((ventes['client_id'] != null) && (ventes['date'] != null)) {
if (list.isNotEmpty) {
for (var sells in list) {
if ((sells.clientid == ventes['client_id']) &&
(sells.date == ventes['date'])) {
trouve = true;
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
sells.produits.add(produit);
sells.montant += produit.couttotale;
}
}
if (!trouve) {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits = List<Produit>();
vente.produits.add(produit);
list.add(vente);
}
trouve = false;
} else {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
vente.produits = List<Produit>();
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits.add(produit);
list.add(vente);
}
}
}
}
setState(() {});
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
Size size = MediaQuery.of(context).size;
screenHeight = size.height;
screenWidth = size.width;
return Scaffold(
backgroundColor: backgroundColor,
body: Stack(
children: <Widget>[
menu(context),
dashboard(context),
],
),
);
}
int tag = 0;
List<String> options = [
'Date',
'Client',
'Montant',
];
final elements1 = [
"Alger",
"Harach",
"Beo",
"Said Hamdine",
"Ain Naadja",
"Kouba",
"Garidi",
];
_openPopup(context) {
DateTime mindate, maxdate;
Alert(
context: context,
title: "Filtres",
style: AlertStyle(
backgroundColor: Colors.grey[200],
titleStyle: TextStyle(
fontFamily: 'Mom cake',
fontWeight: FontWeight.bold,
fontSize: 34)),
content: SizedBox(
width: screenWidth,
height: screenHeight * 0.6,
child: Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text("Trier par :",
style: TextStyle(
fontFamily: 'Mom cake',
fontWeight: FontWeight.bold,
fontSize: 34)),
Row(
children: [
Expanded(
child: ChipsChoice<int>.single(
value: tag,
onChanged: (val) => setState(() => tag = val),
choiceItems: C2Choice.listFrom<int, String>(
source: options,
value: (i, v) => i,
label: (i, v) => v,
),
choiceStyle: C2ChoiceStyle(
color: Colors.black,
borderRadius:
const BorderRadius.all(Radius.circular(10)),
),
),
),
],
),
Text("Secteur :"),
MyStatefulWidget(),
Text("Client : "),
MyStatefulWidget2(),
Text("Montant de vente"),
Row(
children: [
SizedBox(
width: 110.0,
child: TextFormField(
decoration: InputDecoration(
labelText: 'MIN',
border: OutlineInputBorder(),
),
),
),
SizedBox(
width: 8,
child: Divider(
thickness: 2.0,
),
),
SizedBox(
width: 110.0,
child: TextFormField(
decoration: InputDecoration(
labelText: 'MAX',
border: OutlineInputBorder(),
),
),
),
],
),
Text("Date de vente"),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 150.0,
height: 70,
child: IconButton(
icon: Icon(
Icons.date_range_rounded,
),
onPressed: () async {
final List<DateTime> picked =
await DateRagePicker.showDatePicker(
context: context,
initialFirstDate: new DateTime.now(),
initialLastDate: new DateTime.now()
.add(new Duration(days: 7)),
firstDate: new DateTime(2015),
lastDate: new DateTime(2030));
if (picked != null && picked.length == 2) {
mindate = picked[1];
maxdate = picked[2];
}
},
),
),
],
),
],
),
),
),
buttons: [
DialogButton(
onPressed: () => Navigator.pop(context),
child: Text(
"Filtrer",
style: TextStyle(color: Colors.white, fontSize: 17),
),
),
DialogButton(
onPressed: () => Navigator.pop(context),
child: Text(
"Réinitialiser",
style: TextStyle(color: Colors.white, fontSize: 17),
),
)
]).show();
}
Widget menu(context) {
return ... some widget ...
}
Widget dashboard(context) {
return AnimatedPositioned(
duration: duration,
top: 0,
bottom: 0,
left: isCollapsed ? 0 : 0.6 * screenWidth,
right: isCollapsed ? 0 : -0.2 * screenWidth,
child: ScaleTransition(
scale: _scaleAnimation,
child: Material(
animationDuration: duration,
borderRadius: BorderRadius.all(Radius.circular(40)),
elevation: 8,
color: backgroundColor,
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
physics: ClampingScrollPhysics(),
child: Container(
padding: const EdgeInsets.only(left: 16, right: 16, top: 37),
child: SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
children: [
InkWell(
child: Icon(Icons.menu, color: Colors.white),
onTap: () {
setState(() {
if (isCollapsed) {
_controller.forward();
} else
_controller.reverse();
isCollapsed = !isCollapsed;
});
},
),
Text("Historique",
style:
TextStyle(fontSize: 24, color: Colors.white)),
IconButton(
icon: CircleAvatar(
radius: 15.0,
backgroundImage:
AssetImage('assets/images/search.png'),
),
onPressed: () {
_openPopup(context);
setState(() {});
})
],
),
ListView.builder(
scrollDirection: Axis.vertical,
shrinkWrap: true,
itemCount: list.length,
itemBuilder: (context, index) {
return HistoryItem(
client_id: list[index].clientid,
date: list[index].date,
clientnom: list[index].clientnom,
screenWidth: MediaQuery.of(context).size.width,
documentSnapshot: list[index].data,
montant: list[index].montant,
produits: list[index].produits,
);
},
),
],
),
),
),
),
),
),
);
}
}
class Vente {
DocumentSnapshot data;
String clientid;
String clientnom;
String date;
double montant;
List<Produit> produits;
Vente(
{@required this.clientid,
this.date,
this.data,
this.clientnom,
this.produits,
this.montant});
}
class Produit {
String nom;
int baseprice;
double prixpromo;
double couttotale;
int nbarticle;
Produit(
{this.baseprice,
this.nbarticle,
this.nom,
this.couttotale,
this.prixpromo});
}
解决方案
您可以使用FutureBuilder小部件。用FutureBuilder包装您的ListView.builder。
FutureBuilder<List<Vente>(
future: getVente(),
builder: (context, stream){
if(stream.hasData){
return ListView.builder();
} else {
return CircularProgressIndicator() ;
}
}
)
更新您的 getVente() 方法
Future<List<Vente>> getVente() async {
bool trouve = false;
await for (QuerySnapshot snapshots
in FirebaseFirestore.instance.collection('vente').snapshots()) {
for (var ventes in snapshots.docs) {
if ((ventes['client_id'] != null) && (ventes['date'] != null)) {
if (list.isNotEmpty) {
for (var sells in list) {
if ((sells.clientid == ventes['client_id']) &&
(sells.date == ventes['date'])) {
trouve = true;
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
sells.produits.add(produit);
sells.montant += produit.couttotale;
}
}
if (!trouve) {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits = List<Produit>();
vente.produits.add(produit);
list.add(vente);
}
trouve = false;
} else {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
vente.produits = List<Produit>();
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits.add(produit);
list.add(vente);
}
}
}
}
return list; // Add this here
}
解释
FutureBuilder<T>
将等待未来完成。
在这种情况下,FutureBuilder<void>
什么都没有,所以你的方法getVente()
返回 void。它将等到代码完成,并通知构建器。在这种情况下,您不需要调用getVente()
initState 中的方法,因为 FutureBuilder 会为您完成。
您也可以选择FutureBuilder<List<Vente>>
哪个更好,但是您需要对代码进行相当多的更改。它需要一个 Vente 对象列表,您可以在构建器方法中使用它。
future.connectionState == ConnectionState.waiting
将检查未来是否仍在连接中,并且尚未完成。在这种情况下,构建器将显示一个CircularProgressIndicator()
,
当 future 完成时,它将返回 ListView.builder 方法。
如果需要,您可以找到有关FutureBuilder的更多信息。
如果您希望在值更改时更新小部件,也可以使用StreamBuilder 。
StreamBuilder<List<Vente>(
stream: getVente(),
builder: (context, future){
if(future.hasData){
return ListView.builder();
} else {
return CircularProgressIndicator() ;
}
}
)
更新您的 getVente() 方法
Stream<List<Vente>> getVente() async* {
bool trouve = false;
await for (QuerySnapshot snapshots
in FirebaseFirestore.instance.collection('vente').snapshots()) {
for (var ventes in snapshots.docs) {
if ((ventes['client_id'] != null) && (ventes['date'] != null)) {
if (list.isNotEmpty) {
for (var sells in list) {
if ((sells.clientid == ventes['client_id']) &&
(sells.date == ventes['date'])) {
trouve = true;
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
sells.produits.add(produit);
sells.montant += produit.couttotale;
}
}
if (!trouve) {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits = List<Produit>();
vente.produits.add(produit);
list.add(vente);
}
trouve = false;
} else {
vente = Vente(
clientid: ventes['client_id'],
clientnom: ventes['client_name'],
date: ventes['date'],
data: ventes,
montant: ventes['couttotale'],
);
vente.produits = List<Produit>();
produit = Produit();
produit.baseprice = ventes['baseprice'];
produit.couttotale = ventes['couttotale'];
produit.nbarticle = ventes['nb_product'];
produit.prixpromo = ventes['prixpromo'];
produit.nom = ventes['marque'];
vente.produits.add(produit);
list.add(vente);
}
}
}
}
yield list; // Add this here
}
推荐阅读
- unity3d - 如何在 Photon Unity 中获取封闭房间的名称?
- python - 从其他模块访问 python namedtuple _fields
- java - 有没有更快的方法将 python numpy 传递给 JPype 中的 java 数组
- java - java中调用另一个方法时触发一个方法(或者没有aop怎么做aop)
- git - 查找没有 PR 的旧分支
- c# - Visual Studio 2017 - 如何从错误消息中删除路径
- c++ - 尝试在矢量上使用擦除功能时“没有匹配的调用功能”
- flutter - analysis_options.yaml 中有多个包含项?
- javascript - 从JS中的字符串替换特定元素(唯一或重复)
- constraints - 在约束块内使用函数