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
相关产品推荐
相关产品推荐

