Flutter Bloc状态不更新:输入内容无法同步至UI界面
Flutter Bloc状态不更新问题:弹窗编辑地址后UI无法同步输入内容
问题描述
使用Flutter Bloc时遇到状态不更新问题,弹窗编辑地址后,UI无法同步显示输入内容。已在输入框onChanged方法触发GetInput事件,也尝试在保存按钮onPressed中添加相同逻辑,但均无效。
相关代码
Bloc文件
import 'package:bloc/bloc.dart'; part 'address_event.dart'; part 'address_state.dart'; class AddressBloc extends Bloc<AddressEvent, AddressState> { AddressBloc() : super(AddressInitial()); @override Stream<AddressState> mapEventToState(AddressEvent event) async* { if (event is GetInput) { yield* _mapGetInputEventToState(event); } } @override Stream<AddressState> _mapGetInputEventToState(GetInput event) async* { yield AddressInitial(inputText: event.inputText); } }
Event文件
part of 'address_bloc.dart'; abstract class AddressEvent {} class GetInput extends AddressEvent { String inputText; GetInput(this.inputText); }
State文件
part of 'address_bloc.dart'; abstract class AddressState {} class AddressInitial extends AddressState { String? inputText; AddressInitial({this.inputText}); }
UI文件Bloc部分
BlocBuilder<AddressBloc, AddressState>( bloc: addressBloc, builder: (context, state) { if(state is AddressInitial){ return Row( children: [ Icon(Icons.location_on, size: 20), Space(24), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Address", textAlign: TextAlign.start, style: TextStyle( fontWeight: FontWeight.w900, fontSize: 21), ), Space(4), if(textEditingController.text.isNotEmpty) Text( "${state.inputText}", textAlign: TextAlign.start, style: TextStyle( color: Colors.grey, fontSize: 16, ), ), if(textEditingController.text.isEmpty) Text( "2911, sec 9/11, Hisar", textAlign: TextAlign.start, style: TextStyle( color: Colors.grey, fontSize: 16, ), ), ], ), ), Space(8), IconButton( onPressed: () { showDialog( context: context, builder: (BuildContext context) { return Dialog( child: Container( height: 250, width: 500, padding: const EdgeInsets.all( 20), child: SingleChildScrollView( child: Column( children: [ CustomTextField( controller: textEditingController, maxLines: 3, title: 'Address', hasTitle: true, initialValue: '', onChanged: (value) { addressBloc.add(GetInput(textEditingController.text)); }), CustomTextField( maxLines: 1, title: 'LandMark', hasTitle: true, initialValue: '', onChanged: (value) {}), ElevatedButton( style: ElevatedButton .styleFrom( backgroundColor: Colors .white), onPressed: () { Navigator.pop( context); }, child: Text( 'Save', style: Theme.of( context) .textTheme .headline5! .copyWith( color: Colors .black), ), ) ], ), ), ), ); }); }, icon: Icon(Icons.edit)), ], ); } else{ return SizedBox(height: 10,); } }, ),
解决方案
1. 重写状态类的相等性判断方法
Bloc通过比较状态对象的相等性决定是否触发UI重建,默认==比较对象引用而非属性值。修改AddressInitial类,重写==和hashCode:
part of 'address_bloc.dart'; abstract class AddressState {} class AddressInitial extends AddressState { String? inputText; AddressInitial({this.inputText}); @override bool operator ==(Object other) => identical(this, other) || other is AddressInitial && runtimeType == other.runtimeType && inputText == other.inputText; @override int get hashCode => inputText.hashCode; }
2. UI逻辑改为依赖Bloc状态而非TextEditingController
原UI用textEditingController.text判断显示内容,导致与Bloc状态不同步,改为直接使用Bloc的state.inputText:
BlocBuilder<AddressBloc, AddressState>( bloc: addressBloc, builder: (context, state) { if(state is AddressInitial){ return Row( children: [ Icon(Icons.location_on, size: 20), Space(24), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( "Address", textAlign: TextAlign.start, style: TextStyle( fontWeight: FontWeight.w900, fontSize: 21), ), Space(4), // 直接依赖Bloc状态判断 if(state.inputText?.isNotEmpty ?? false) Text( "${state.inputText}", textAlign: TextAlign.start, style: TextStyle( color: Colors.grey, fontSize: 16, ), ), if(state.inputText?.isEmpty ?? true) Text( "2911, sec 9/11, Hisar", textAlign: TextAlign.start, style: TextStyle( color: Colors.grey, fontSize: 16, ), ), ], ), ), Space(8), IconButton( onPressed: () { // 弹窗打开时同步Bloc状态到控制器 textEditingController.text = state.inputText ?? ''; showDialog( context: context, builder: (BuildContext context) { return Dialog( child: Container( height: 250, width: 500, padding: const EdgeInsets.all(20), child: SingleChildScrollView( child: Column( children: [ CustomTextField( controller: textEditingController, maxLines: 3, title: 'Address', hasTitle: true, initialValue: '', // 直接传onChanged的value即可,无需取控制器文本 onChanged: (value) { addressBloc.add(GetInput(value)); }), CustomTextField( maxLines: 1, title: 'LandMark', hasTitle: true, initialValue: '', onChanged: (value) {}), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: Colors.white), onPressed: () { Navigator.pop(context); }, child: Text( 'Save', style: Theme.of(context) .textTheme .headline5! .copyWith(color: Colors.black), ), ) ], ), ), ), ); }); }, icon: Icon(Icons.edit)), ], ); } else{ return SizedBox(height: 10,); } }, ),
额外优化点
- 弹窗打开时,将Bloc当前的
inputText赋值给textEditingController,确保编辑初始值与UI显示一致。 onChanged回调直接使用参数value,无需通过textEditingController.text获取输入内容,逻辑更简洁。
内容的提问来源于stack exchange,提问作者Pulkit Aggarwal
相关产品推荐
相关产品推荐

