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

Flutter TableCalendar v3.0.2 加载REST API数据按选中日期展示实现问题

实现方案

步骤1:补充状态变量

在你的页面State类中新增以下状态,用于存储接口返回的数据和日期-事件映射关系:

late Future<List<ObjectName>> _dataFuture;
List<ObjectName> _allEvents = [];
// 核心映射结构:key为日期(时分秒清零),value为对应日期的所有数据对象
Map<DateTime, List<ObjectName>> _eventMap = {};

@override
void initState() {
  super.initState();
  _dataFuture = getData();
}

步骤2:用FutureBuilder包裹整体布局

将原有的TableCalendar外层套FutureBuilder,用于处理接口加载状态、构建日期映射:

@override
Widget build(BuildContext context) {
  return FutureBuilder<List<ObjectName>>(
    future: _dataFuture,
    builder: (context, snapshot) {
      if (snapshot.connectionState == ConnectionState.waiting) {
        return const Center(child: CircularProgressIndicator());
      }
      if (snapshot.hasError) {
        return Center(child: Text('加载失败:${snapshot.error}'));
      }
      // 接口请求成功,构建日期-事件映射
      _allEvents = snapshot.data!;
      _eventMap.clear();
      for (var event in _allEvents) {
        // 日期统一转成UTC且时分秒清零,避免时区问题导致匹配失败
        final dateKey = DateTime.utc(event.date.year, event.date.month, event.date.day);
        if (_eventMap[dateKey] == null) _eventMap[dateKey] = [];
        _eventMap[dateKey]!.add(event);
      }
      // 返回列布局:上方日历 + 下方选中日期的数据展示
      return Column(
        children: [
          // 这里放修改后的TableCalendar
          _buildCalendar(),
          // 下方展示区域
          const SizedBox(height: 16),
          _buildSelectedDayContent(),
        ],
      );
    },
  );
}

步骤3:修改TableCalendar配置

新增事件加载逻辑,让日历自动给有数据的日期加标记点,同时注意修改firstDay适配历史数据:

Widget _buildCalendar() {
  return TableCalendar(
    // 注意:原firstDay是当前时间,要展示2020年的数据需要改早
    firstDay: DateTime(2020),
    lastDay: DateTime(DateTime.now().year + 10),
    focusedDay: _focusedDay,
    calendarFormat: _calendarFormat,
    // 新增:事件加载器,返回对应日期的所有数据
    eventLoader: (day) {
      final dateKey = DateTime.utc(day.year, day.month, day.day);
      return _eventMap[dateKey] ?? [];
    },
    selectedDayPredicate: (day) {
      return isSameDay(_selectedDay, day);
    },
    onDaySelected: (selectedDay, focusedDay) {
      if (!isSameDay(_selectedDay, selectedDay)) {
        setState(() {
          _selectedDay = selectedDay;
          _focusedDay = focusedDay;
        });
      }
    },
    onFormatChanged: (format) {
      if (_calendarFormat != format) {
        setState(() {
          _calendarFormat = format;
        });
      }
    },
    onPageChanged: (focusedDay) {
      _focusedDay = focusedDay;
    },
  );
}

步骤4:实现选中日期的数据展示逻辑

Widget _buildSelectedDayContent() {
  if (_selectedDay == null) return const SizedBox();
  final dateKey = DateTime.utc(_selectedDay!.year, _selectedDay!.month, _selectedDay!.day);
  final dayEvents = _eventMap[dateKey] ?? [];
  if (dayEvents.isEmpty) {
    return const Padding(
      padding: EdgeInsets.all(16),
      child: Text('当天暂无数据'),
    );
  }
  return Expanded(
    child: ListView.builder(
      padding: const EdgeInsets.symmetric(horizontal: 16),
      itemCount: dayEvents.length,
      itemBuilder: (context, index) {
        final event = dayEvents[index];
        return Card(
          child: Padding(
            padding: const EdgeInsets.all(12),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(event.name, style: const TextStyle(fontWeight: FontWeight.bold)),
                const SizedBox(height: 4),
                Text(event.description),
              ],
            ),
          ),
        );
      },
    ),
  );
}

注意事项

  1. 确保你的ObjectName类的fromJson方法正确解析了嵌套的date字段,示例结构如下:
class ObjectName {
  final String id;
  final String name;
  final String description;
  final DateTime date;

  ObjectName({
    required this.id,
    required this.name,
    required this.description,
    required this.date,
  });

  factory ObjectName.fromJson(Map<String, dynamic> json) {
    final dateJson = json['date'] as Map<String, dynamic>;
    return ObjectName(
      id: json['id'],
      name: json['name'],
      description: json['description'],
      date: DateTime(dateJson['year'], dateJson['month'], dateJson['day']),
    );
  }
}
  1. 所有日期匹配统一用UTC时间或者都用本地时间,避免时区差异导致isSameDay判断出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 03:36:02