Flutter/Dart DropdownMenu修改Locale调用setState后不更新问题
问题原因
- DropdownMenu复用旧实例:Locale变化时,组件虽执行了
build并生成新的选项列表,但由于DropdownMenu未设置与Locale绑定的唯一key,Flutter会复用旧的组件实例,导致内部选项未更新。 - 选中值与新选项不匹配:原代码直接将翻译后的文本存入
TextEditingController,Locale变化后,旧的文本(如英文"Dwarf")不在新的选项列表(如法文"Nain")中,DropdownMenu无法匹配到有效选项,显示异常。 - initialSelection仅初始化生效:
initialSelection仅在DropdownMenu第一次构建时生效,后续build中修改该参数不会触发选中状态更新。
修复方案
1. 用固定key管理选中状态
不再存储翻译后的文本到TextEditingController,而是存储种族的唯一标识key(如'elf'),这样Locale变化时,可通过key获取对应的新翻译值,保证选中状态的一致性。
2. 给DropdownMenu添加Locale绑定的key
通过ValueKey(Localizations.localeOf(context).languageCode)作为DropdownMenu的key,当Locale变化时,key值改变,Flutter会销毁旧组件并重建新实例,强制加载新的选项列表。
3. 同步更新选中值
在didChangeDependencies中,确保TextEditingController的key始终存在于新的races映射中,避免出现无效key导致的选中异常。
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; class RacesToWidget extends StatefulWidget { final TextEditingController controller; // 存储种族key,如'elf' const RacesToWidget(this.controller, {super.key}); @override State<StatefulWidget> createState() => _RacesToWidgetState(); } class _RacesToWidgetState extends State<RacesToWidget> { TextEditingController get controller => widget.controller; Map<String, String> races = {}; @override void didChangeDependencies() { // 更新种族翻译映射 races = { 'elf': AppLocalizations.of(context).elf, 'dwarf': AppLocalizations.of(context).dwarf, 'gnome': AppLocalizations.of(context).gnome, 'halfling': AppLocalizations.of(context).halfling, 'human': AppLocalizations.of(context).human, 'vran': AppLocalizations.of(context).vran, 'werebbubb': AppLocalizations.of(context).werebbubb, 'witcher': AppLocalizations.of(context).witcher }; // 初始化或校验选中key的有效性 if (controller.text.isEmpty || !races.containsKey(controller.text)) { controller.text = races.keys.first; } super.didChangeDependencies(); } @override Widget build(BuildContext context) { print(races.values.toList()); final selectedText = races[controller.text] ?? races.values.first; return Column(children: [ Center( child: DropdownMenu<String>( // 绑定Locale作为key,确保Locale变化时重建组件 key: ValueKey(Localizations.localeOf(context).languageCode), initialSelection: selectedText, enableFilter: false, enableSearch: false, // 自定义输入框显示选中的翻译文本 inputDecorationTheme: const InputDecorationTheme( border: OutlineInputBorder(), ), onSelected: (String? value) { // 根据选中的翻译文本找到对应的key final selectedKey = races.entries.firstWhere( (entry) => entry.value == value, orElse: () => races.entries.first, ).key; setState(() => controller.text = selectedKey); }, dropdownMenuEntries: races.entries .map((entry) => DropdownMenuEntry<String>( value: entry.value, label: entry.value)) .toList())) ]); } }
额外说明
如果必须保留TextEditingController存储翻译文本的逻辑,可在didChangeDependencies中添加旧文本到新文本的映射:
// 示例:旧英文文本到新文本的映射(需根据实际key对应) final oldToNewMap = { 'Dwarf': races['dwarf'], 'Elf': races['elf'], // 其他种族映射... }; if (oldToNewMap.containsKey(controller.text)) { controller.text = oldToNewMap[controller.text]!; } else { controller.text = races.values.first; }
但这种方式维护成本高,推荐使用固定key管理选中状态的方案。
内容的提问来源于stack exchange,提问作者Adeven
相关产品推荐
相关产品推荐

