将数据从 Firebase 加载到 Flutter 中的 DropdownButton
Loading data from Firebase into a DropdownButton in Flutter
我是 Flutter with Firebase 的新手,我正在尝试将存储在 Firebase 中的一些数组加载到 DropdownButton 中。
当我从按钮调用这段代码时,它可以工作。它 returns 我可以在屏幕上打印的饮料清单:
Future<List<String>> get drinks async {
QuerySnapshot docs = await _constantes.getDocuments();
List<String> res = List();
List<Map<String, dynamic>> datos = List();
for (var d in docs.documents) {
datos.add(d.data);
}
for (var d in datos[0]['drinks'].toList()) {
res.add(d.toString());
}
return res;
}
但我的问题是我想将此列表加载到 DropdownButton 中,以便用户可以在应用程序显示表单时选择其中一种饮料:
DropdownButtonFormField(
hint: Text('Choose a drink'),
value: _currentDrink ?? 'Water',
items: _db.drinks.then((drinks) {
List<DropdownMenuItem> datos = List();
for (var d in drinks) {
datos.add(DropdownMenuItem(
value: d,
child: Text(d),
));
}
return datos;
}),
onChanged: (val) => setState(() => _currentDrink = val),
),
但它不起作用,因为结果是 Future。
我该如何解决?
谢谢。
分配一个空列表[]到dropdown,直到取到饮料,当取到饮料时我们将分配饮料list.Drinks列表将在我们的future之后得到项目completed.You需要在initState中调用这个future您的方法因此,当页面打开时,它会获取饮料,然后将其分配给饮料 list.Dropdown 将保持为空,直到获取饮料。
(如果您想在下拉菜单中显示进度指示器,直到在未来的构建器中提取饮料包装下拉菜单)
List<String> drinks = List();
Future<List<String>> get drinks async {
QuerySnapshot docs = await _constantes.getDocuments();
List<String> res = List();
List<Map<String, dynamic>> datos = List();
for (var d in docs.documents) {
datos.add(d.data);
}
for (var d in datos[0]['drinks'].toList()) {
res.add(d.toString());
}
setState(() {
drinks = res;
});
return res;
}
DropdownButtonFormField(
hint: Text('Choose a drink'),
value: _currentDrink ?? 'Water',
items: drinks == null? []: drinks.map((drink) {
return DropdownMenuItem<String>(
child: Text(drink),
value: drink,
);
}).toList(),
onChanged: (val) => setState(() => _currentDrink = val),
),
将其包裹在 StreamBuilder
中。假设 _constantes 是您的 firebase 集合,而不是使用 _constantes.getDocuments()
return 来自 _constantes.snapshots()
的流进行查询:
StreamBuilder<List<DocumentSnapshot>>(
stream: _drinkStream,
builder: (context, snapshot) {
return snapshot.hasData
? DropdownButton(
onChanged: (value) {},
items: [
for (var child in snapshot.data)
DropdownMenuItem(
child: Text(
child.data['name'],
),
value: child,
),
],
)
: Container();
},
)
您可以在从 firebase 获取数据后构建下拉小部件,如果您想在加载数据或未找到数据之前显示水,那么以下解决方案可能最适合您。
在方法注释部分是针对您的情况,未注释部分是为了演示。
class DeleteWidget extends StatefulWidget {
const DeleteWidget({Key key}) : super(key: key);
@override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
String initdata = 'water';
List<String> _getdata = List();
@override
void initState() {
super.initState();
getdatafromAPI();
}
void getdatafromAPI() async {
/*
_db.drinks.then((drinks){
setState((){
_getdata.addAll(drinks);
initdata = _getdata[0];
});
});
*/
await Future.delayed(Duration(seconds: 1));
setState(() {
_getdata.addAll(['coffee', 'tea', 'greentea']);
initdata = _getdata[0];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('test app'),
),
body: Container(
child: Center(
child: DropdownButton(
items: _getdata.length > 0
? _getdata.map((e) {
return DropdownMenuItem<String>(
child: Text(e.toString()),
value: e.toString(),
);
}).toList()
: [
DropdownMenuItem<String>(
child: Text("water"),
value: 'water',
)
],
value: initdata,
onChanged: (value) {
setState(() {
initdata = value;
});
},
),
),
),
);
}
}
我是 Flutter with Firebase 的新手,我正在尝试将存储在 Firebase 中的一些数组加载到 DropdownButton 中。
当我从按钮调用这段代码时,它可以工作。它 returns 我可以在屏幕上打印的饮料清单:
Future<List<String>> get drinks async {
QuerySnapshot docs = await _constantes.getDocuments();
List<String> res = List();
List<Map<String, dynamic>> datos = List();
for (var d in docs.documents) {
datos.add(d.data);
}
for (var d in datos[0]['drinks'].toList()) {
res.add(d.toString());
}
return res;
}
但我的问题是我想将此列表加载到 DropdownButton 中,以便用户可以在应用程序显示表单时选择其中一种饮料:
DropdownButtonFormField(
hint: Text('Choose a drink'),
value: _currentDrink ?? 'Water',
items: _db.drinks.then((drinks) {
List<DropdownMenuItem> datos = List();
for (var d in drinks) {
datos.add(DropdownMenuItem(
value: d,
child: Text(d),
));
}
return datos;
}),
onChanged: (val) => setState(() => _currentDrink = val),
),
但它不起作用,因为结果是 Future。
我该如何解决?
谢谢。
分配一个空列表[]到dropdown,直到取到饮料,当取到饮料时我们将分配饮料list.Drinks列表将在我们的future之后得到项目completed.You需要在initState中调用这个future您的方法因此,当页面打开时,它会获取饮料,然后将其分配给饮料 list.Dropdown 将保持为空,直到获取饮料。 (如果您想在下拉菜单中显示进度指示器,直到在未来的构建器中提取饮料包装下拉菜单)
List<String> drinks = List();
Future<List<String>> get drinks async {
QuerySnapshot docs = await _constantes.getDocuments();
List<String> res = List();
List<Map<String, dynamic>> datos = List();
for (var d in docs.documents) {
datos.add(d.data);
}
for (var d in datos[0]['drinks'].toList()) {
res.add(d.toString());
}
setState(() {
drinks = res;
});
return res;
}
DropdownButtonFormField(
hint: Text('Choose a drink'),
value: _currentDrink ?? 'Water',
items: drinks == null? []: drinks.map((drink) {
return DropdownMenuItem<String>(
child: Text(drink),
value: drink,
);
}).toList(),
onChanged: (val) => setState(() => _currentDrink = val),
),
将其包裹在 StreamBuilder
中。假设 _constantes 是您的 firebase 集合,而不是使用 _constantes.getDocuments()
return 来自 _constantes.snapshots()
的流进行查询:
StreamBuilder<List<DocumentSnapshot>>(
stream: _drinkStream,
builder: (context, snapshot) {
return snapshot.hasData
? DropdownButton(
onChanged: (value) {},
items: [
for (var child in snapshot.data)
DropdownMenuItem(
child: Text(
child.data['name'],
),
value: child,
),
],
)
: Container();
},
)
您可以在从 firebase 获取数据后构建下拉小部件,如果您想在加载数据或未找到数据之前显示水,那么以下解决方案可能最适合您。
在方法注释部分是针对您的情况,未注释部分是为了演示。
class DeleteWidget extends StatefulWidget {
const DeleteWidget({Key key}) : super(key: key);
@override
_DeleteWidgetState createState() => _DeleteWidgetState();
}
class _DeleteWidgetState extends State<DeleteWidget> {
String initdata = 'water';
List<String> _getdata = List();
@override
void initState() {
super.initState();
getdatafromAPI();
}
void getdatafromAPI() async {
/*
_db.drinks.then((drinks){
setState((){
_getdata.addAll(drinks);
initdata = _getdata[0];
});
});
*/
await Future.delayed(Duration(seconds: 1));
setState(() {
_getdata.addAll(['coffee', 'tea', 'greentea']);
initdata = _getdata[0];
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('test app'),
),
body: Container(
child: Center(
child: DropdownButton(
items: _getdata.length > 0
? _getdata.map((e) {
return DropdownMenuItem<String>(
child: Text(e.toString()),
value: e.toString(),
);
}).toList()
: [
DropdownMenuItem<String>(
child: Text("water"),
value: 'water',
)
],
value: initdata,
onChanged: (value) {
setState(() {
initdata = value;
});
},
),
),
),
);
}
}