Flutter中showCupertinoModalPopup日期选择器结合Bloc状态UI不更新
问题解决:Bloc状态已发射但UI未更新
状态已成功发射,列表数据已更新(打印可见),但UI始终不刷新。弹窗正常弹出,时间能设置到任务中,但UI组件没有更新。尝试过在showCupertinoBottomSheet的.then中调用emit,也用过StatefulBuilder,均无效。
核心原因
问题出在Equatable的状态比较逻辑和列表的引用复用:
- 直接修改了原状态中列表的元素,没有创建新的列表引用。Equatable在比较
listOfDailyRoutineOption时,只判断列表的引用是否相同,而非内部元素是否变化。引用不变的情况下,Bloc会认为状态没有更新,不会触发UI重建。 - 如果
DailyRoutineModel是可变类,直接修改元素属性也会导致Equatable无法识别变化(因为元素引用没变)。
修复方案
1. 修改Cubit中的showDatePicker方法,创建新的列表和模型实例
不要直接复用原列表的引用,而是创建列表副本,并通过模型的copyWith方法生成新的实例(确保模型是不可变的):
void showDatePicker(context, index) async { DateTime date = DateTime.now(); await showCupertinoModalPopup( context: context, builder: (BuildContext builder) { return Container( height: MediaQuery.of(context).copyWith().size.height * 0.25, color: Colors.white, child: Column( children: [ Expanded( child: CupertinoDatePicker( mode: CupertinoDatePickerMode.time, onDateTimeChanged: (value) { date = value; }, initialDateTime: DateTime.now(), ), ), CupertinoButton( child: const Text('Done'), onPressed: () { String formattedTime = DateFormat.jm().format(date); // 1. 创建原列表的副本,生成新的引用 var updatedList = List<DailyRoutineModel>.from(state.listOfDailyRoutineOption); // 2. 使用copyWith创建新的模型实例,替换原位置的元素 updatedList[index] = updatedList[index].copyWith(time: formattedTime); // 3. 发射包含新列表的状态 emit(state.copyWith(listOfDailyRoutineOption: updatedList)); Navigator.of(context).pop(); }, ) ], ), ); }, ); }
2. 确保DailyRoutineModel是不可变类并继承Equatable
如果你的DailyRoutineModel还不是不可变的,需要修改成以下结构,确保Equatable能正确比较模型实例:
class DailyRoutineModel extends Equatable { final String title; final String time; const DailyRoutineModel({required this.title, required this.time}); @override List<Object> get props => [title, time]; // 添加copyWith方法,用于生成新的实例 DailyRoutineModel copyWith({ String? title, String? time, }) { return DailyRoutineModel( title: title ?? this.title, time: time ?? this.time, ); } }
3. 验证状态类的copyWith方法
你的OnBoardState的copyWith方法已经正确传递新的列表引用,无需修改,但要确保传入的是新创建的列表(步骤1已经做到)。
为什么之前的尝试无效
- 在
.then中调用emit:核心问题是状态没有被识别为变化,即使延迟emit,引用还是原列表,Equatable仍然认为状态未变。 - 使用
StatefulBuilder:UI组件依赖Bloc状态,Bloc没有触发重建,StatefulBuilder也无法感知到状态变化。
内容的提问来源于stack exchange,提问作者Osama Buzdar
相关产品推荐
相关产品推荐

