Flutter中BlocBuilder内TextField状态更新时失焦问题求助
解决BlocBuilder更新时TextField失焦的问题
问题根源是BlocBuilder每次状态变化会重建整个子组件树,包括TextField在内的所有元素都会被重新实例化,直接导致焦点丢失——哪怕加了FocusNode,没做针对性处理也没用。
下面是几个实用的解决办法:
方案1:用BlocSelector缩小重建范围
只让需要更新的容器背景色部分响应状态变化,TextField所在的子树保持稳定,避免被重建:
return Container( // 只监听description的变化,仅更新color值 color: BlocSelector<MyCubit, MyState, Color?>( selector: (state) => (state.description == null || state.description!.isEmpty) ? Colors.red : null, builder: (context, color) => color, ), child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("title"), const Divider(color: constants.grey), TextField( maxLines: null, controller: _controller, ), ], ), ), );
方案2:把TextField抽成独立StatefulWidget
将TextField封装成单独的组件,这样BlocBuilder重建时,这个独立组件的状态会被Flutter保留,不会重新初始化,焦点自然不会丢失:
// 单独封装的TextField组件 class DescriptionTextField extends StatefulWidget { final TextEditingController controller; const DescriptionTextField({super.key, required this.controller}); @override State<DescriptionTextField> createState() => _DescriptionTextFieldState(); } class _DescriptionTextFieldState extends State<DescriptionTextField> { late FocusNode _focusNode; @override void initState() { super.initState(); _focusNode = FocusNode(); } @override void dispose() { _focusNode.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return TextField( maxLines: null, controller: widget.controller, focusNode: _focusNode, ); } } // 原组件中使用这个封装好的组件 return BlocBuilder<MyCubit, MyState>( builder: (context, state) { return Container( color: (state.description == null || state.description!.isEmpty) ? Colors.red : null, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("title"), const Divider(color: constants.grey), DescriptionTextField(controller: _controller), ], ), ), ); }, );
方案3:手动保存并恢复焦点
如果不想抽组件,可以在BlocBuilder重建后,手动判断并恢复焦点:
// 在组件内定义FocusNode late FocusNode _textFieldFocusNode; @override void initState() { super.initState(); _textFieldFocusNode = FocusNode(); } @override void dispose() { _textFieldFocusNode.dispose(); super.dispose(); } // 构建方法 return BlocBuilder<MyCubit, MyState>( builder: (context, state) { // 先标记重建前是否处于聚焦状态 final wasFocused = _textFieldFocusNode.hasFocus; // 组件构建完成后恢复焦点 WidgetsBinding.instance.addPostFrameCallback((_) { if (wasFocused) { FocusScope.of(context).requestFocus(_textFieldFocusNode); } }); return Container( color: (state.description == null || state.description!.isEmpty) ? Colors.red : null, child: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text("title"), const Divider(color: constants.grey), TextField( maxLines: null, controller: _controller, focusNode: _textFieldFocusNode, ), ], ), ), ); }, );
内容的提问来源于stack exchange,提问作者fanfan
相关产品推荐
相关产品推荐

