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

Flutter TableCalendar滑动切换卡顿,如何优化页面过渡流畅度?

解决TableCalendar滑动切换月份卡顿的问题

你的卡顿根源主要在markerBuilder里的重复计算和复杂Widget嵌套,和是否预加载3个页面关系不大,先从以下几点优化:

1. 缓存重复计算的结果

每个日历单元格build时,你都在重复执行农历转换、节日数据遍历这些耗时操作,滑动时几百个单元格同时计算,必然导致卡顿。可以用缓存来避免重复计算:

示例:缓存农历转换结果

在组件类里定义缓存Map:

final Map<DateTime, Lunar> _lunarCache = {};
final Map<DateTime, String> _lunarDayCache = {};

然后在markerBuilder里优先读取缓存,无结果再计算:

// 缓存农历日期转换结果
Lunar lunarDate = _lunarCache.putIfAbsent(date, () {
  return LunarSolarConverter.solarToLunar(
    Solar(
      solarYear: date.year,
      solarMonth: date.month,
      solarDay: date.day,
    ),
  );
});

// 缓存农历日显示文本
final lunarDay = _lunarDayCache.putIfAbsent(date, () => getLunarDay(date));

优化节日数据查询

提前将农历节日对应的阳历日期计算好并存入_holidays,这样不需要每次转换农历日期再查询,减少临时计算量。

2. 简化单元格内的Widget结构

你在每个单元格里嵌套了ListView,这是非常重量级的Widget——节日数量有限,用Column就能替代,大幅减少布局开销:

替换ListView为Column

// 替换原有的Container+ListView部分
Container(
  margin: const EdgeInsets.only(top: 0, left: 2, right: 2),
  height: 45,
  child: Column(
    mainAxisSize: MainAxisSize.min,
    children: [
      if (lunarDateTime.day == 14 || lunarDateTime.day == 15)
        Icon(
          Icons.brightness_1,
          color: Color.fromARGB(255, 249, 249, 0),
        ),
      ...holidayEvents.map((event) {
        index++;
        return Container(
          margin: EdgeInsets.symmetric(vertical: 2.0),
          decoration: BoxDecoration(
            color: solarHolidaysColors[index],
            borderRadius: BorderRadius.circular(2.0),
          ),
          padding: EdgeInsets.only(left: 1),
          child: Text(
            '$event',
            style: TextStyle(color: Colors.white, fontSize: 10),
            overflow: TextOverflow.ellipsis,
          ),
        );
      }),
      ...lunarEvents.map((event) {
        index++;
        return Container(
          margin: EdgeInsets.symmetric(vertical: 2.0),
          decoration: BoxDecoration(
            color: lunarHolidaysColors[index],
            borderRadius: BorderRadius.circular(2.0),
          ),
          padding: EdgeInsets.only(left: 1),
          child: Text(
            '$event',
            style: TextStyle(color: Colors.white, fontSize: 10),
            overflow: TextOverflow.ellipsis,
          ),
        );
      }),
    ],
  ),
),

3. 关于预加载3个日历页面

TableCalendar基于PageView实现,默认已经会预加载前后各1个页面(总共3个),所以不需要额外设置。如果优化上述两点后还是卡顿,可以尝试调整PageView的缓存范围,但这只是治标,核心还是要优化单元格的构建性能。

额外优化点

  • 去掉markerBuilder里的print语句,避免IO开销;
  • 缓存isSameDay(date, DateTime.now())的结果,避免重复创建DateTime.now()对象;
  • 把TextStyle提前定义为类成员变量,避免每次build都创建新样式。

内容的提问来源于stack exchange,提问作者Hồ Nhật Tân

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:16:13