Flutter中对应的DropDownButtonFormField

Corresponding DropDownButtonFormFields in Flutter

我正在实现相应的下拉菜单(其中第二个下拉菜单的选项取决于第一个下拉菜单),它使用以下格式的对象列表:

List<State> states = [
  new State(stateId: 1, stateName: "New York", cities: [
    new City(cityId: 1, cityName: "New York City"),
    new City(cityId: 2, cityName: "Buffalo") ...

小部件代码如下:

children: <Widget>[
                DropdownButtonFormField<int>(
                  decoration: InputDecoration(labelText: 'State'),
                  value: selectedStateId,
                  items: states.map((State state) {
                    return new DropdownMenuItem<int>(
                      value: state.stateId,
                      child: new Text(states.singleWhere((x) => x.stateId == state.stateId).stateName),
                    );
                  }).toList(),
                  onChanged: (int newStateId) {
                    setState(() {
                      this.selectedCityId = states.singleWhere((x) => x.stateId == newStateId).cities[0].cityId; // set to first city for this state
                      this.selectedStateId = = newStateId;
                    });
                  },
                ),
                DropdownButtonFormField<int>(
                  decoration: InputDecoration(labelText: 'City'),
                  value: selectedCityId,
                  items: states.singleWhere((x) => x.stateId == selectedStateId)
                      .cities
                      .map((City city) {
                    return new DropdownMenuItem<int>(
                      value: city.cityId,
                      child: new Text(states
                          .singleWhere((x) => x.stateId == selectedStateId).cities.singleWhere((x) => x.cityId == city.cityId).cityName),
                    );
                  }).toList(),
                  onChanged: (int newCityId) {
                    setState(() {
                      this.selectedCityId = newCityId;
                    });
                  },
                )
              ],

当我在此示例中更改状态下拉列表时,出现错误: “应该只有一项具有 [DropdownButton] 的值:1。 检测到具有相同值的零个或两个或更多 [DropdownMenuItem]。

上述错误中的“1”对应于更改状态之前所选城市的值,所以我知道该错误与它仍在寻找旧的 selectedCityId 而不再是在项目列表中,但我不确定为什么我在 setState 中更改了该值。我认为,这个问题的一个关键是,如果我只是将 DropDownButtonFormField 更改为常规 DropDownButtons,则完全相同的代码仍然有效,但我想使用前者附带的内置标签文本。

编辑
您可以使用 key: UniqueKey() int City DropdownButtonFormField

DropdownButtonFormField<int>(
      key: UniqueKey(),
      decoration: InputDecoration(labelText: 'City'),

您可以复制粘贴运行下面的完整代码
您可以将 selectedStateIdselectedCityId 设置为 states 的属性
不能直接设置成selectedStateId = 1这样的值,因为系统会比较地址
代码片段

  int selectedStateId;
  int selectedCityId;

  @override
  void initState() {
    selectedStateId = states[0].stateId;
    selectedCityId = states[0].cities[0].cityId;
    super.initState();
  }

工作演示

完整代码

import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class City {
  int cityId;
  String cityName;
  City({this.cityId, this.cityName});
}

class CountryState {
  int stateId;
  String stateName;
  List<City> cities;
  CountryState({this.stateId, this.stateName, this.cities});
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  List<CountryState> states = [
    CountryState(stateId: 1, stateName: " York", cities: [
      City(cityId: 1, cityName: "York City"),
      City(cityId: 2, cityName: "Buffalo")
    ]),
    CountryState(stateId: 2, stateName: "A", cities: [
      City(cityId: 3, cityName: "A1"),
      City(cityId: 4, cityName: "A2")
    ])
  ];

  int selectedStateId;
  int selectedCityId;

  @override
  void initState() {
    selectedStateId = states[0].stateId;
    selectedCityId = states[0].cities[0].cityId;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            DropdownButtonFormField<int>(
              decoration: InputDecoration(labelText: 'State'),
              value: selectedStateId,
              items: states.map((CountryState state) {
                return DropdownMenuItem<int>(
                  value: state.stateId,
                  child: Text(states
                      .singleWhere((x) => x.stateId == state.stateId)
                      .stateName),
                );
              }).toList(),
              onChanged: (int StateId) {
                setState(() {
                  this.selectedCityId = states
                      .singleWhere((x) => x.stateId == StateId)
                      .cities[0]
                      .cityId; // set to first city for this state
                  this.selectedStateId = StateId;
                });
              },
            ),
            DropdownButtonFormField<int>(
              key: UniqueKey(),
              decoration: InputDecoration(labelText: 'City'),
              value: selectedCityId,
              items: states
                  .singleWhere((x) => x.stateId == selectedStateId)
                  .cities
                  .map((City city) {
                return DropdownMenuItem<int>(
                  value: city.cityId,
                  child: Text(states
                      .singleWhere((x) => x.stateId == selectedStateId)
                      .cities
                      .singleWhere((x) => x.cityId == city.cityId)
                      .cityName),
                );
              }).toList(),
              onChanged: (int CityId) {
                setState(() {
                  this.selectedCityId = CityId;
                });
              },
            )
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

我在 Flutter 问题板上发布了这个示例,它们无法在最新的稳定版本(截至本评论时为 1.20.2)上复制。我升级了我的 flutter 版本(我在 1.17.1)和相同的代码 运行 没有问题,所以对于遇到同样问题的任何人我建议更新你的 flutter 版本。