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

Flutter:BlocSelector重建后TextFormField丢失焦点问题求助

解决Flutter Bloc动态表单输入框失去焦点问题

问题根源

你当前使用UniqueKey()作为TextFormField的key,每次Bloc状态更新触发BlocSelector重建时,所有输入框都会生成新的UniqueKey。Flutter会将这些视为全新的组件,销毁旧输入框并重建,直接导致输入焦点丢失。

解决方案

核心是给每个输入框分配稳定且唯一的Key,避免重建时组件被误判为新元素。最优方案是让每个输入项携带唯一标识,而非仅存储字符串:

  1. 定义带唯一ID的输入项实体
class AnswerItem {
  final String id;
  String value;

  AnswerItem({required this.id, required this.value});
}
  1. 调整Bloc状态与事件处理
    将原状态中的List<String> answerList改为List<AnswerItem> answerList,同步更新事件逻辑:
  • 添加新项时生成唯一ID(可使用DateTime.now().microsecondsSinceEpoch.toString()或Uuid包)
  • 修改、删除操作基于索引或ID定位项(推荐用ID更稳定)
  1. 更新UI层代码
    用ValueKey(item.id)作为TextFormField的key,确保组件重建时key保持稳定:
class AddQuestionScreenBody extends StatelessWidget {
  AddQuestionScreenBody({super.key});
  final GlobalKey _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.only(right: 15.0, left: 15.0),
      child: Form(
        key: _formKey,
        child: Column(
          children: [
            BlocSelector<AddQuestionBloc, AddQuestionState, List<AnswerItem>>(
              selector: (state) => state.answerList,
              builder: (context, answerList) {
                return Column(
                  children: [
                    for (int i = 0; i < answerList.length; i++)
                      Padding(
                        padding: const EdgeInsets.only(bottom: 15.0),
                        child: TextFormField(
                          // 使用基于唯一ID的稳定Key
                          key: ValueKey(answerList[i].id),
                          initialValue: answerList[i].value,
                          validator: (value) {
                            if (value == null || value.isEmpty) {
                              return "Answer is required";
                            }
                            return null;
                          },
                          onChanged: (value) {
                            context.read<AddQuestionBloc>().add(
                                  OnChangeAnswerElement(
                                    index: i,
                                    value: value,
                                  ),
                                );
                          },
                          decoration: InputDecoration(
                            label: Text('Answer ${i + 1}'),
                            suffixIconColor: Colors.redAccent,
                            suffixIcon: IconButton(
                              onPressed: () {
                                context.read<AddQuestionBloc>().add(
                                      OnRemoveAnswerElement(i),
                                    );
                              },
                              icon: const Icon(Icons.remove),
                            ),
                          ),
                        ),
                      ),
                    ElevatedButton(
                      onPressed: () {
                        context.read<AddQuestionBloc>().add(
                              OnAddAnswerElement(),
                            );
                      },
                      child: const Icon(Icons.add),
                    ),
                  ],
                );
              },
            ),
          ],
        ),
      ),
    );
  }
}

临时替代方案(不推荐)

如果暂时不想修改状态结构,可尝试用ValueKey('answer_${answerList[i]}_$i')作为key,但当存在重复输入值或删除中间项时,仍可能出现焦点问题,仅适用于简单场景。

内容的提问来源于stack exchange,提问作者Justin Timbersaw

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 22:05:32