如何在Flutter中结合Riverpod使用日期范围选择器
解决Flutter中Riverpod结合日期范围选择器的问题
核心修改要点
- 将
Trip类改为支持复制更新的不可变类(添加copyWith方法) - 使用
StateNotifier和StateNotifierProvider管理Trip列表的状态,实现状态更新与UI同步 - 在Trip页面中通过provider更新Trip的日期范围,确保修改实时反映到界面
修改后的完整代码
import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; void main() { runApp( const ProviderScope( child: MyApp(), ), ); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return const MaterialApp( debugShowCheckedModeBanner: false, title: 'Riverpod DateRange Picker', home: HomeScreen(), ); } } // 修改Trip类,添加copyWith方法用于更新日期范围 class Trip { final String name; final DateTimeRange dateTimeRange; Trip(this.name, this.dateTimeRange); // 生成新的Trip对象,仅更新指定字段 Trip copyWith({DateTimeRange? dateTimeRange}) { return Trip( name, dateTimeRange ?? this.dateTimeRange, ); } } // 创建StateNotifier管理Trip列表的状态 class TripListNotifier extends StateNotifier<List<Trip>> { TripListNotifier() : super([ Trip('Test 1', DateTimeRange(start: DateTime(2023, 1, 3), end: DateTime(2023, 1, 6))) ]); // 更新指定Trip的日期范围 void updateTripDate(Trip targetTrip, DateTimeRange newRange) { state = state.map((trip) { if (trip.name == targetTrip.name) { // 实际项目建议用唯一ID标识Trip return trip.copyWith(dateTimeRange: newRange); } return trip; }).toList(); } } // 定义对应的provider final tripListProvider = StateNotifierProvider<TripListNotifier, List<Trip>>((ref) { return TripListNotifier(); }); class HomeScreen extends ConsumerWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { // 从provider获取Trip列表 final trips = ref.watch(tripListProvider); return Scaffold( appBar: AppBar(title: const Text('Riverpod DateRange Picker')), body: ListView( children: [ for (final trip in trips) ListTile( title: Text(trip.name), onTap: () { Navigator.push( context, MaterialPageRoute<void>( builder: (BuildContext context) => TripScreen(trip: trip))); }, ), ], ), ); } } class TripScreen extends ConsumerWidget { const TripScreen({Key? key, required this.trip}) : super(key: key); final Trip trip; @override Widget build(BuildContext context, WidgetRef ref) { // 监听当前Trip的最新状态 final currentTrip = ref.watch(tripListProvider).firstWhere((t) => t.name == trip.name); void _showDateRangePicker() async { final DateTimeRange? result = await showDateRangePicker( context: context, locale: const Locale('en', 'GB'), initialDateRange: currentTrip.dateTimeRange, saveText: 'Done', firstDate: DateTime(2022, 1, 1), lastDate: DateTime(2030, 12, 31), ); if (result != null) { // 通过provider更新Trip的日期范围 ref.read(tripListProvider.notifier).updateTripDate(currentTrip, result); } } return WillPopScope( onWillPop: () { Navigator.pop(context); return Future.value(false); }, child: Scaffold( backgroundColor: Colors.white, appBar: AppBar( title: Text(currentTrip.name), ), body: Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[ IconButton( icon: const Icon(Icons.calendar_month), onPressed: _showDateRangePicker, ), Text( 'Start: ${DateFormat('dd/MM/yyyy').format(currentTrip.dateTimeRange.start)}'), Text( 'End: ${DateFormat('dd/MM/yyyy').format(currentTrip.dateTimeRange.end)}'), ], )))); } }
关键说明
- Trip类的copyWith方法:由于Trip是不可变类,每次修改都需要生成新对象,避免直接修改原对象导致状态无法被Riverpod追踪。
- StateNotifier管理状态:
TripListNotifier负责维护Trip列表,提供updateTripDate方法更新指定Trip的日期范围,状态修改后会自动通知UI刷新。 - UI状态同步:在TripScreen中通过
ref.watch监听Trip列表变化,确保显示最新数据;选择日期后通过ref.read调用notifier的更新方法完成状态修改。
内容的提问来源于stack exchange,提问作者jcwhall
相关产品推荐
相关产品推荐

