You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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,会导致逻辑混乱,出现重复拉取或者错误清空事件的问题。
修复方案
  1. 在页面初始化生命周期(比如initState)里主动调用一次eventsMap(),拉取初始月份的事件数据,等数据赋值给events后再调用setState触发首次渲染。
  2. 调整事件更新的执行顺序:月份变更时,先清空旧的events数据,再执行eventsMap()拉取新月份事件;如果eventsMap()是异步方法,必须等新事件全部写入events变量后,再调用setState更新组件状态,把新的events传入Calendar组件。
  3. 统一判断逻辑,修正类型不匹配的问题,月份对比要保证两边都是int类型的月份值,避免判断失效。

内容的提问来源于stack exchange,提问作者GRaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 13:48:21