Flutter Calendar初始/切月时事件不显示 点击日期才显示问题
问题描述
日历组件基础运行正常,但存在明确异常:切换月份时日历日期上的事件标记不可见,仅在点击任意日期后事件才会正常显示。
该日历组件支持在日期上以圆点形式标记事件,同时在日历下方以列表形式展示事件内容。切换月份时会触发onMonthChanged回调拉取对应月份的待展示事件,其余功能运行正常,核心异常点为:初始加载时日期上的事件不会显示,点击任意日期后事件才会正常渲染。
相关代码
Calendar组件完整调用实现
Calendar( initialDate: month2, startOnMonday: false, onMonthChanged: (m) => { print("onMonthChanged called: " + m.month.toString()), print(month2), if (m.month != month2.month) { setState(() { month2 = m; year2 = m.year; eventsMap(); }), events.clear(), } }, selectedColor: Colors.blue, todayColor: Colors.red, eventColor: Colors.green, eventDoneColor: Colors.amber, bottomBarColor: Colors.deepOrange, events: events, isExpanded: true, dayOfWeekStyle: TextStyle( fontSize: 12, color: Colors.blueGrey, fontWeight: FontWeight.bold, ), bottomBarTextStyle: TextStyle( color: Colors.white, ), hideArrows: false, weekDays: const ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], )
onMonthChanged回调单独实现
onMonthChanged: (m) => { print("onMonthChanged called: " + m.month.toString()), if (m.month != month2) { setState(() { month2 = m.month; year2 = m.year; eventsMap(); }), events.clear(), } },
Calendar组件类定义
class Calendar extends StatefulWidget { final ValueChanged<DateTime>? onDateSelected; final ValueChanged<DateTime>? onMonthChanged; final ValueChanged<bool>? onExpandStateChanged; final ValueChanged? onRangeSelected; final ValueChanged<CleanCalendarEvent>? onEventSelected; final bool isExpandable; final DayBuilder? dayBuilder; final EventListBuilder? eventListBuilder; final bool hideArrows; final bool hideTodayIcon; final Map<DateTime, List<CleanCalendarEvent>>? events; final Color? selectedColor; final Color? todayColor; final String todayButtonText; final Color? eventColor; final Color? eventDoneColor; final DateTime? initialDate; final bool isExpanded; final List<String> weekDays; final String? locale; final bool startOnMonday; final bool hideBottomBar; final TextStyle? dayOfWeekStyle; final TextStyle? bottomBarTextStyle; final Color? bottomBarArrowColor; final Color? bottomBarColor; final String? expandableDateFormat; }
问题根因
一共三个核心错误导致该异常:
- 初始加载逻辑缺失:Calendar组件初始化时不会主动触发
onMonthChanged回调,现有逻辑没有在组件首次加载时调用eventsMap()拉取初始月份的事件,初始状态下events列表为空,自然不会显示事件标记。 - 代码执行顺序和更新时机完全错误:Dart中
setState会先同步执行传入的回调,再标记组件为脏状态等待下一帧重建。你把events.clear()写在setState外部,意味着setState回调执行完(不管eventsMap()是同步还是异步),都会立刻清空events列表:如果eventsMap()是同步赋值逻辑,赋值完成后立刻被清空,下一帧重建时拿到的是空事件列表;如果eventsMap()是异步拉取接口的逻辑,调用时仅发起请求,回调执行完就会走到events.clear(),等接口返回数据赋值给events时,没有额外调用setState触发更新,组件不会主动重绘。后续点击日期时会触发Calendar组件内部的状态更新,此时如果异步事件已经拉取完成,就会正常渲染出事件标记。 - 判断条件存在类型不匹配bug:贴出的两段
onMonthChanged判断逻辑不一致,一段判断m.month != month2.month(int类型月份值对比),另一段判断m.month != month2(int类型值和DateTime对象对比),后者判断永远为true,会导致逻辑混乱,出现重复拉取或者错误清空事件的问题。
修复方案
- 在页面初始化生命周期(比如
initState)里主动调用一次eventsMap(),拉取初始月份的事件数据,等数据赋值给events后再调用setState触发首次渲染。 - 调整事件更新的执行顺序:月份变更时,先清空旧的
events数据,再执行eventsMap()拉取新月份事件;如果eventsMap()是异步方法,必须等新事件全部写入events变量后,再调用setState更新组件状态,把新的events传入Calendar组件。 - 统一判断逻辑,修正类型不匹配的问题,月份对比要保证两边都是int类型的月份值,避免判断失效。
内容的提问来源于stack exchange,提问作者GRaw
相关产品推荐
相关产品推荐

