将数据从 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;
              });
            },
          ),
        ),
      ),
    );
  }
}