You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter DropdownButton异常:显示国家名称绑定国家代码时出错

问题描述

我希望Dropdown组件显示国家名称,但选中后获取对应国家代码。编写了CountryDropdown组件,初始_selectedCountry设为"Austria",但当DropdownMenuItem的value设为国家代码(如"au")时出现错误;若将value设为"Austria",或显示文本设为"au"而value为"Austria"则正常运行,请问这是什么原因?

错误截图

错误截图

代码示例

class CountryDropdown extends StatefulWidget {
  const CountryDropdown({Key? key}) : super(key: key);

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

class _CountryDropdownState extends State<CountryDropdown> {
  String _selectedCountry = "Austria";

  List<DropdownMenuItem<String>> get dropdownItems {
    List<DropdownMenuItem<String>> menuItems = [
      const DropdownMenuItem(child: Text("Austria"), value: "au"),
      const DropdownMenuItem(child: Text("Belgium"), value: "be"),
      const DropdownMenuItem(child: Text("Croatia"), value: "hr"),
    ];
    return menuItems;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(10.0),
      child: DropdownButton<String>(
        value: _selectedCountry,
        hint: const Text('Select a country'),
        onChanged: (newValue) {
          setState(() {
            _selectedCountry = newValue!;
          });
        },
        items: dropdownItems,
      ),
    );
  }
}
问题原因

Flutter的DropdownButton有严格的匹配规则:初始设置的value必须存在于所有DropdownMenuItem的value集合中。你这里初始_selectedCountry设为"Austria",但所有DropdownMenuItem的value都是国家代码("au"、"be"、"hr"),"Austria"不在这个集合里,因此触发断言错误:There should be exactly one item with [DropdownButton]'s value: Austria.

当你把value设为"Austria",或者把显示文本换成代码、value用国家名称时,初始值和MenuItem的value完全匹配,所以不会报错。

解决方案

要实现“显示名称,选中后获取代码”的需求,有两种实用方案:

方案1:统一用国家代码作为value,调整初始值

直接把初始_selectedCountry设为对应国家的代码,保持MenuItem的child显示名称:

class _CountryDropdownState extends State<CountryDropdown> {
  // 初始值改为奥地利的国家代码"au"
  String _selectedCountry = "au";

  List<DropdownMenuItem<String>> get dropdownItems {
    List<DropdownMenuItem<String>> menuItems = [
      const DropdownMenuItem(child: Text("Austria"), value: "au"),
      const DropdownMenuItem(child: Text("Belgium"), value: "be"),
      const DropdownMenuItem(child: Text("Croatia"), value: "hr"),
    ];
    return menuItems;
  }

  // 其余代码保持不变
}

这种方式简单直接,初始值和MenuItem的value匹配,选中后_selectedCountry就是国家代码,显示的是名称,完全符合需求。

方案2:自定义数据类绑定名称和代码

如果需要同时处理名称和代码的关联逻辑,可以创建一个数据类来封装两者:

// 定义国家数据类,绑定名称和代码
class Country {
  final String name;
  final String code;

  Country(this.name, this.code);
}

然后修改Dropdown的泛型为Country:

class _CountryDropdownState extends State<CountryDropdown> {
  // 初始选中奥地利的Country对象
  Country _selectedCountry = Country("Austria", "au");

  List<DropdownMenuItem<Country>> get dropdownItems {
    List<DropdownMenuItem<Country>> menuItems = [
      DropdownMenuItem(child: Text("Austria"), value: Country("Austria", "au")),
      DropdownMenuItem(child: Text("Belgium"), value: Country("Belgium", "be")),
      DropdownMenuItem(child: Text("Croatia"), value: Country("Croatia", "hr")),
    ];
    return menuItems;
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(10.0),
      child: DropdownButton<Country>(
        value: _selectedCountry,
        hint: const Text('Select a country'),
        // 自定义选中项的显示内容
        selectedItemBuilder: (context) {
          return dropdownItems.map((item) => Text(item.value!.name)).toList();
        },
        onChanged: (newValue) {
          setState(() {
            _selectedCountry = newValue!;
            // 选中后可直接通过_selectedCountry.code获取国家代码
            print("选中的国家代码:${_selectedCountry.code}");
          });
        },
        items: dropdownItems,
      ),
    );
  }
}

这种方式扩展性更强,适合需要同时使用名称和代码的复杂场景。


内容的提问来源于stack exchange,提问作者Lee Casey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 15:17:43