Flutter table_calendar选中日期样式不更新问题求助
问题:table_calendar选中日期样式不更新
使用table_calendar制作日历组件,想要实现选中日期切换功能。调用setState后已确认状态变量已更新,但选中日期的组件样式未发生变化,不清楚问题原因。
代码示例
import 'dart:collection'; import 'package:flutter/material.dart'; import 'package:table_calendar/table_calendar.dart'; import 'dart:developer' as developer; import '../widgets/table_calendar_util.dart'; class LessonBody extends StatefulWidget { const LessonBody({super.key}); @override State<LessonBody> createState() => _LessonBodyState(); } class _LessonBodyState extends State<LessonBody> { // Using a `LinkedHashSet` is recommended due to equality comparison override final Set<DateTime> _selectedDays = LinkedHashSet<DateTime>( equals: isSameDay, hashCode: getHashCode, ); CalendarFormat _calendarFormat = CalendarFormat.week; DateTime _focusedDay = DateTime.now(); DateTime _selectedDay = DateTime.now(); Map<DateTime, List<Event>>? _noteMapByDay; @override Widget build(BuildContext context) { return SafeArea( child: Column( children: [ Stack( children: [ TableCalendar<Event>( calendarStyle: const CalendarStyle( todayDecoration: BoxDecoration( color: Colors.green, shape: BoxShape.circle, ), markerDecoration: BoxDecoration( color: Colors.red, shape: BoxShape.rectangle, ), ), firstDay: kFirstDay, lastDay: kLastDay, focusedDay: _focusedDay, calendarFormat: _calendarFormat, eventLoader: (day) { if (_noteMapByDay != null) { return _noteMapByDay![day] ?? []; } else { return []; } }, startingDayOfWeek: StartingDayOfWeek.monday, selectedDayPredicate: (day) { // Use values from Set to mark multiple days as selected return _selectedDays.contains(day); }, onDaySelected: (selectedDay, focusedDay) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; developer.log('focusedDay : $_focusedDay'); developer.log('selectedDay : $_selectedDay'); }); developer.log('select'); }, onFormatChanged: (format) { if (_calendarFormat != format) { setState(() { _calendarFormat = format; developer.log('onFormatChanged : ${format.name}'); }); } }, onPageChanged: (focusedDay) { _focusedDay = focusedDay; }, ), // 주, 2주, 월 단위로 보여주기 Positioned( right: 60, top: 9, child: Align( alignment: Alignment.topRight, child: TextButton.icon( onPressed: () { setState(() { switch (_calendarFormat) { case CalendarFormat.week: _calendarFormat = CalendarFormat.twoWeeks; break; case CalendarFormat.twoWeeks: _calendarFormat = CalendarFormat.month; break; case CalendarFormat.month: _calendarFormat = CalendarFormat.week; break; default: } }); }, icon: const Icon( Icons.calendar_month_rounded, color: Colors.green, ), label: _calendarFormat == CalendarFormat.week ? const Text( '주', style: TextStyle(color: Colors.green), ) : _calendarFormat == CalendarFormat.twoWeeks ? const Text( '2주', style: TextStyle(color: Colors.green), ) : const Text( '월', style: TextStyle(color: Colors.green), )), ), ), ], ), const SizedBox( height: 15, ), ], ), ); } }
问题原因
你的selectedDayPredicate方法是通过判断_selectedDays.contains(day)来标记选中日期的,但在onDaySelected回调里,只更新了_selectedDay变量,完全没修改_selectedDays集合。所以即使调用了setState,组件判断选中状态的依据没变化,样式自然不会更新。
解决方法
单选日期场景
在onDaySelected里清空原有选中项,添加新选中日期:
onDaySelected: (selectedDay, focusedDay) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; // 清空原有选中项,添加新选中日期(单选逻辑) _selectedDays.clear(); _selectedDays.add(selectedDay); developer.log('focusedDay : $_focusedDay'); developer.log('selectedDay : $_selectedDay'); }); developer.log('select'); },
多选日期场景
改成切换日期选中状态的逻辑:
onDaySelected: (selectedDay, focusedDay) { setState(() { _selectedDay = selectedDay; _focusedDay = focusedDay; // 多选逻辑:切换日期的选中状态 if (_selectedDays.contains(selectedDay)) { _selectedDays.remove(selectedDay); } else { _selectedDays.add(selectedDay); } developer.log('focusedDay : $_focusedDay'); developer.log('selectedDay : $_selectedDay'); }); developer.log('select'); },
补充初始化逻辑
建议在初始化时把默认选中日期加入_selectedDays,避免初始状态下选中样式不显示:
@override void initState() { super.initState(); _selectedDays.add(_selectedDay); }
内容的提问来源于stack exchange,提问作者황희윤
相关产品推荐
相关产品推荐

