Flutter中SfDateRangePicker无法加载SharedPreferences存储的初始日期范围
问题根因
SfDateRangePicker的initialSelectedRange属性仅在组件首次初始化构建时生效,后续组件更新时该属性的变更不会被响应。- 你在
DateRangeFilterModel的构造函数中调用的loadDateRange是异步方法,SfDateRangePicker首次构建时,异步读取还未完成,model.dateRange为null,等SharedPreferences读取完成触发notifyListeners时,组件只会局部更新,不会重新初始化日期选择器,所以出现Text能正常展示、但日期选择器没有更新选中范围的问题。
解决方案
方案1:添加唯一Key强制组件重建
给SfDateRangePicker添加ValueKey,Key的值绑定model.dateRange,当dateRange更新时,Key会变化,Flutter就会销毁旧的日期选择器组件,用新的初始值重建,代码修改如下:
Consumer<DateRangeFilterModel>( builder: (context, model, child) => Column( children: [ Text(model.dateRange.toString()), SfDateRangePicker( // 新增这一行,绑定dateRange作为唯一Key key: ValueKey(model.dateRange), initialSelectedRange: model.dateRange, showTodayButton: false, enablePastDates: false, selectionMode: DateRangePickerSelectionMode.range, minDate: DateTime.now(), onSelectionChanged: (DateRangePickerSelectionChangedArgs args) { if (args.value is PickerDateRange) { final DateTime? startDate = args.value.startDate; final DateTime? endDate = args.value.endDate; if (startDate != null && endDate != null) { context .read<DateRangeFilterModel>() .setDateRange(PickerDateRange(startDate, endDate)); } } }, ), ], ), ),
该方案改动最小,适合大部分场景。
方案2:使用控制器手动控制选中范围
通过DateRangePickerController主动控制选中的日期范围,不受初始值限制,性能更优:
- 首先在页面状态中声明控制器
final DateRangePickerController _pickerController = DateRangePickerController();
- 在
Consumer中监听dateRange变化,手动给控制器赋值:
Consumer<DateRangeFilterModel>( builder: (context, model, child) { // 监听dateRange变化,更新控制器的选中范围 if (model.dateRange != _pickerController.selectedRange) { WidgetsBinding.instance.addPostFrameCallback((_) { _pickerController.selectedRange = model.dateRange; }); } return Column( children: [ Text(model.dateRange.toString()), SfDateRangePicker( // 绑定控制器 controller: _pickerController, showTodayButton: false, enablePastDates: false, selectionMode: DateRangePickerSelectionMode.range, minDate: DateTime.now(), onSelectionChanged: (DateRangePickerSelectionChangedArgs args) { if (args.value is PickerDateRange) { final DateTime? startDate = args.value.startDate; final DateTime? endDate = args.value.endDate; if (startDate != null && endDate != null) { context .read<DateRangeFilterModel>() .setDateRange(PickerDateRange(startDate, endDate)); } } }, ), ], ); }, ),
内容的提问来源于stack exchange,提问作者tmsbrndz
相关产品推荐
相关产品推荐

