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

Flutter/Dart DropdownMenu修改Locale调用setState后不更新问题

问题原因
  1. DropdownMenu复用旧实例:Locale变化时,组件虽执行了build并生成新的选项列表,但由于DropdownMenu未设置与Locale绑定的唯一key,Flutter会复用旧的组件实例,导致内部选项未更新。
  2. 选中值与新选项不匹配:原代码直接将翻译后的文本存入TextEditingController,Locale变化后,旧的文本(如英文"Dwarf")不在新的选项列表(如法文"Nain")中,DropdownMenu无法匹配到有效选项,显示异常。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 13:48:14