1. 简介
table_calendar 是 Flutter 生态中功能强大的日历组件,支持多种视图切换、事件标记、日期范围选择等核心功能,适合需集成日历功能的应用场景(如日程管理、预约系统等)。其高度可定制化的特性使其能适配不同的 UI 需求。
2. 基础配置
安装
yaml
dependencies:
table_calendar: ^3.0.1 # 请使用最新版本
最简实现
dart
import 'package:table_calendar/table_calendar.dart';
TableCalendar(
firstDay: DateTime(2020),
lastDay: DateTime(2030),
focusedDay: DateTime.now(),
selectedDayPredicate: (day) {
return isSameDay(_selectedDay, day);
},
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
},
)
核心参数说明:
firstDay/lastDay:日历显示范围(必传)focusedDay:当前聚焦的日期(控制滚动位置,必传)selectedDayPredicate:判断日期是否被选中的条件onDaySelected:日期选择回调(返回选中日期和新聚焦日期)
3. 核心属性全解析
3.1. 核心基础属性
| 属性名 | 类型 | 说明 |
|---|---|---|
firstDay |
DateTime |
日历显示的起始日期(必传) |
lastDay |
DateTime |
日历显示的结束日期(必传) |
focusedDay |
DateTime |
当前聚焦的日期(必传,控制日历滚动位置) |
selectedDayPredicate |
bool Function(DateTime) |
判断日期是否被选中的条件 |
onDaySelected |
void Function(DateTime, DateTime) |
单个日期选中回调(选中日期+聚焦日期) |
onPageChanged |
void Function(DateTime) |
日历页面切换时回调(返回新聚焦日期) |
3.2. 视图控制属性
| 属性名 | 类型 | 说明 |
|---|---|---|
calendarFormat |
CalendarFormat |
日历展示格式(month/week/twoWeeks) |
onFormatChanged |
void Function(CalendarFormat) |
视图格式切换回调 |
availableCalendarFormats |
Map<CalendarFormat, String> |
允许的视图格式及对应显示文本 |
pageJumpingEnabled |
bool |
是否允许点击表头月份快速跳转页面(默认true) |
weekNumbersVisible |
bool |
是否显示周数(默认false) |
weekNumberStyle |
TextStyle |
周数文本样式 |
示例:
dart
TableCalendar(
// ...基础参数
calendarFormat: _calendarFormat,
onFormatChanged: (format) {
setState(() {
_calendarFormat = format;
});
},
availableCalendarFormats: {
CalendarFormat.month: '月',
CalendarFormat.week: '周',
CalendarFormat.twoWeeks: '两周',
},
)
3.3. 范围选择属性
| 属性名 | 类型 | 说明 |
|---|---|---|
rangeStartDay |
DateTime? |
范围选择的起始日期 |
rangeEndDay |
DateTime? |
范围选择的结束日期 |
rangeSelectionMode |
RangeSelectionMode |
范围选择模式(toggledOff/toggledOn/forced) |
onRangeSelected |
void Function(DateTime?, DateTime?, DateTime) |
范围选择回调(起始/结束/聚焦日期) |
rangeDayPredicate |
bool Function(DateTime) |
判断日期是否允许被纳入范围选择 |
示例:
dart
RangeSelectionMode _rangeSelectionMode = RangeSelectionMode.toggledOff;
DateTime? _rangeStart;
DateTime? _rangeEnd;
TableCalendar(
// ...基础参数
rangeStartDay: _rangeStart,
rangeEndDay: _rangeEnd,
rangeSelectionMode: _rangeSelectionMode,
onRangeSelected: (start, end, focusedDay) {
setState(() {
_rangeStart = start;
_rangeEnd = end;
_rangeSelectionMode = RangeSelectionMode.toggledOn;
_selectedDay = null; // 清除单个选中
});
},
)
3.4. 事件与标记属性
| 属性名 | 类型 | 说明 |
|---|---|---|
eventLoader |
List<Object> Function(DateTime) |
加载指定日期的事件数据 |
calendarBuilders |
CalendarBuilders |
自定义日历元素构建器(标记/日期等) |
holidayLoader |
List<Object> Function(DateTime) |
加载指定日期的假日数据 |
eventFadeTransitionEnabled |
bool |
事件标记是否启用淡入动画(默认true) |
示例:
dart
// 定义事件数据结构
final Map<DateTime, List> _events = {
DateTime(2023, 10, 15): ['会议', '生日'],
DateTime(2023, 10, 20): ['deadline'],
};
TableCalendar(
// ...其他参数
eventLoader: (day) {
return _events[day] ?? [];
},
calendarBuilders: CalendarBuilders(
markerBuilder: (context, date, events) {
if (events.isEmpty) return SizedBox();
return Positioned(
bottom: 1,
child: Container(
width: 16,
height: 4,
decoration: BoxDecoration(
color: Colors.blue,
borderRadius: BorderRadius.circular(2),
),
),
);
},
),
)
3.5. 样式定制属性
| 属性名 | 类型 | 说明 |
|---|---|---|
calendarStyle |
CalendarStyle |
日历主体样式配置 |
headerStyle |
HeaderStyle |
表头(月份栏)样式配置 |
daysOfWeekStyle |
DaysOfWeekStyle |
星期标题样式配置 |
rowHeight |
double |
日历行高(影响整体高度) |
columnWidth |
double? |
日历列宽(null时自动计算) |
padding |
EdgeInsets |
日历内边距 |
margin |
EdgeInsets |
日历外边距 |
clipBehavior |
Clip |
裁剪行为(默认Clip.hardEdge) |
CalendarStyle 子属性
| 属性名 | 类型 | 说明 |
|---|---|---|
defaultTextStyle |
TextStyle |
默认日期文本样式 |
selectedTextStyle |
TextStyle |
选中日期文本样式 |
todayTextStyle |
TextStyle |
今天日期文本样式 |
weekendTextStyle |
TextStyle |
周末日期文本样式 |
outsideTextStyle |
TextStyle |
显示范围外日期文本样式 |
disabledTextStyle |
TextStyle |
禁用日期文本样式 |
selectedDecoration |
Decoration |
选中日期装饰(背景等) |
todayDecoration |
Decoration |
今天日期装饰 |
defaultDecoration |
Decoration |
默认日期装饰 |
weekendDecoration |
Decoration |
周末日期装饰 |
outsideDecoration |
Decoration |
范围外日期装饰 |
disabledDecoration |
Decoration |
禁用日期装饰 |
rangeStartDecoration |
Decoration |
范围选择起始日期装饰 |
rangeEndDecoration |
Decoration |
范围选择结束日期装饰 |
rangeMiddleDecoration |
Decoration |
范围选择中间日期装饰 |
markersDecoration |
Decoration |
事件标记容器装饰 |
markersMaxCount |
int |
最多显示的事件标记数量 |
markerSize |
double |
事件标记大小 |
markersOffset |
PositionedOffset |
事件标记偏移量 |
canMarkersOverflow |
bool |
标记是否允许溢出日期单元格 |
outsideDaysVisible |
bool |
是否显示范围外的日期(默认true) |
HeaderStyle 子属性
| 属性名 | 类型 | 说明 |
|---|---|---|
formatButtonVisible |
bool |
是否显示视图切换按钮(默认true) |
formatButtonShowsNext |
bool |
切换按钮是否显示下一个格式(默认true) |
formatButtonDecoration |
BoxDecoration |
视图切换按钮装饰 |
formatButtonTextStyle |
TextStyle |
视图切换按钮文本样式 |
leftChevronIcon |
Widget |
左箭头图标 |
rightChevronIcon |
Widget |
右箭头图标 |
titleTextStyle |
TextStyle |
标题(月份)文本样式 |
titleCentered |
bool |
标题是否居中(默认false) |
titleFormatter |
String Function(DateTime, dynamic) |
标题文本格式化器 |
headerPadding |
EdgeInsets |
表头内边距 |
headerMargin |
EdgeInsets |
表头外边距 |
chevronPadding |
EdgeInsets |
箭头图标内边距 |
chevronVisible |
bool |
是否显示箭头图标(默认true) |
样式定制示例:
dart
TableCalendar(
// ...其他参数
calendarStyle: CalendarStyle(
// 选中日期样式
selectedDecoration: BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
// 今天日期样式
todayDecoration: BoxDecoration(
color: Colors.grey[200],
shape: BoxShape.circle,
),
// 周末样式
weekendTextStyle: TextStyle(color: Colors.red),
// 事件标记样式
markersMaxCount: 3, // 最多显示3个标记
markerSize: 6,
),
// 表头样式
headerStyle: HeaderStyle(
formatButtonVisible: false, // 隐藏视图切换按钮
titleCentered: true,
headerPadding: EdgeInsets.symmetric(vertical: 8),
titleTextStyle: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
),
)
3.6. 本地化属性
| 属性名 | 类型 | 说明 |
|---|---|---|
locale |
String? |
本地化语言代码(如'zh_CN'、'en_US') |
daysOfWeekLabels |
List<String> |
星期标签文本(默认按locale生成) |
daysOfWeekLabelsExceptions |
Map<int, String> |
特定星期几的文本覆盖 |
weekNumberLabel |
String |
周数标签文本(默认'W') |
示例:
dart
import 'package:intl/intl.dart';
import 'package:intl/date_symbol_data_local.dart';
// 初始化本地化
initializeDateFormatting().then((_) {
setState(() {});
});
TableCalendar(
// ...其他参数
locale: 'zh_CN', // 支持 'en_US', 'ja_JP' 等
daysOfWeekStyle: DaysOfWeekStyle(
weekdayStyle: TextStyle(),
weekendStyle: TextStyle(color: Colors.red),
),
)
3.7. 交互控制属性
| 属性名 | 类型 | 说明 |
|---|---|---|
enabledDayPredicate |
bool Function(DateTime) |
判断日期是否可交互(默认全部可交互) |
onHeaderTapped |
void Function(DateTime) |
表头点击回调 |
onHeaderLongPressed |
void Function(DateTime) |
表头长按回调 |
onDayLongPressed |
void Function(DateTime, DateTime) |
日期长按回调 |
dragStartBehavior |
DragStartBehavior |
拖拽起始行为(默认start) |
3.8. 高级自定义属性
| 属性名 | 类型 | 说明 |
|---|---|---|
calendarBuilders |
CalendarBuilders |
自定义构建器集合(以下为常用子项) |
- dayBuilder |
Widget Function(BuildContext, DateTime, DateTime, bool, bool, bool, bool, List) |
自定义日期单元格 |
- markerBuilder |
Widget Function(BuildContext, DateTime, List) |
自定义事件标记 |
- headerTitleBuilder |
Widget Function(BuildContext, DateTime) |
自定义表头标题 |
- weekNumberBuilder |
Widget Function(BuildContext, int) |
自定义周数显示 |
transitionDuration |
Duration |
视图切换动画时长(默认200ms) |
pageAnimationEnabled |
bool |
是否启用页面切换动画(默认true) |
4. 性能优化
- 使用
ValueNotifier管理事件数据,避免不必要重建 - 复杂标记使用缓存Widget
- 合理设置
firstDay和lastDay范围
dart
final ValueNotifier<List> _selectedEvents = ValueNotifier([]);
// 监听选中日期变化更新事件
void _updateSelectedEvents() {
_selectedEvents.value = _events[_selectedDay] ?? [];
}
// 构建时使用ValueListenableBuilder
ValueListenableBuilder<List>(
valueListenable: _selectedEvents,
builder: (context, value, _) {
return // 事件列表
},
)
5. 完整配置示例
dart
TableCalendar(
firstDay: DateTime(2020),
lastDay: DateTime(2030),
focusedDay: _focusedDay,
selectedDayPredicate: (day) => isSameDay(_selectedDay, day),
onDaySelected: (selectedDay, focusedDay) {
if (!isSameDay(_selectedDay, selectedDay)) {
setState(() {
_selectedDay = selectedDay;
_focusedDay = focusedDay;
});
}
},
// 视图配置
calendarFormat: _calendarFormat,
onFormatChanged: (format) => setState(() => _calendarFormat = format),
availableCalendarFormats: const {
CalendarFormat.month: '月',
CalendarFormat.week: '周',
},
// 范围选择
rangeStartDay: _rangeStart,
rangeEndDay: _rangeEnd,
rangeSelectionMode: _rangeSelectionMode,
onRangeSelected: (start, end, focusedDay) => setState(() {
_rangeStart = start;
_rangeEnd = end;
_rangeSelectionMode = RangeSelectionMode.toggledOn;
}),
// 事件加载
eventLoader: (day) => _events[day] ?? [],
// 样式定制
calendarStyle: CalendarStyle(
selectedDecoration: const BoxDecoration(
color: Colors.blue,
shape: BoxShape.circle,
),
todayDecoration: BoxDecoration(
color: Colors.grey[200],
shape: BoxShape.circle,
),
markersMaxCount: 3,
),
headerStyle: const HeaderStyle(
titleCentered: true,
formatButtonVisible: false,
),
// 本地化
locale: 'zh_CN',
// 自定义构建器
calendarBuilders: CalendarBuilders(
markerBuilder: (context, date, events) => events.isNotEmpty
? Container(
width: 12,
height: 12,
decoration: const BoxDecoration(
color: Colors.red,
shape: BoxShape.circle,
),
)
: null,
),
)
6. 总结
table_calendar 提供了灵活的日历解决方案,核心关注:
- 基础日期选择与范围选择的状态管理
- 事件标记与自定义样式的视觉定制
- 视图切换与本地化的用户体验优化
- 性能优化技巧(如状态隔离、合理设置范围)
更复杂功能可参考官方文档或Github仓库实现。使用时需注意范围选择与单个选择的互斥性,以及本地化配置的初始化步骤。
本次分享就到这儿啦,我是鹏多多,深耕前端的技术创作者,如果您看了觉得有帮助,欢迎评论,关注,点赞,转发,我们下次见~
PS:在本页按F12,在console中输入document.getElementsByClassName('panel-btn')[0].click();有惊喜哦~
往期文章
- flutter-屏幕自适应插件flutter_screenutil教程全指南
- flutter-使用url_launcher打开链接/应用/短信/邮件和评分跳转等
- flutter图片选择库multi_image_picker_plus和image_picker的对比和使用解析
- 解锁flutter弹窗新姿势:dialog-flutter_smart_dialog插件解读+案例
- flutter-切换状态显示不同组件10种实现方案全解析
- flutter-详解控制组件显示的两种方式Offstage与Visibility
- flutter-使用AnimatedDefaultTextStyle实现文本动画
- flutter-使用SafeArea组件处理各机型的安全距离
- flutter-实现渐变色边框背景以及渐变色文字
- flutter-使用confetti制作炫酷纸屑爆炸粒子动画