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

如何在Flutter中使用FirebaseFirestore作为SfCalendar的数据源

从Firebase Firestore获取数据并绑定到SfCalendar的实现方案

步骤1:修改Meeting类,添加Firestore数据解析构造函数

首先需要给Meeting类添加一个工厂构造函数,用来将Firestore返回的Map数据转换成Meeting实例:

class Meeting {
  Meeting(this.eventName, this.from, this.to, this.background, this.isAllDay);

  String eventName;
  DateTime from;
  DateTime to;
  Color background;
  bool isAllDay;

  // 从Firestore的Map数据生成Meeting对象
  factory Meeting.fromMap(Map<String, dynamic> map) {
    // Firestore存储的时间是Timestamp类型,需转换为DateTime
    final Timestamp fromTs = map['from'] as Timestamp;
    final Timestamp toTs = map['to'] as Timestamp;
    // 颜色存储为十六进制字符串(如"FF0F8644"),转换为Color类型
    final String colorHex = map['background'] as String;
    final Color color = Color(int.parse(colorHex, radix: 16));

    return Meeting(
      map['eventName'] as String,
      fromTs.toDate(),
      toTs.toDate(),
      color,
      map['isAllDay'] as bool,
    );
  }
}

步骤2:编写Firestore数据获取方法

实现异步方法从event集合读取数据,并转换为List<Meeting>:

// 一次性获取所有数据(适合不需要实时更新的场景)
Future<List<Meeting>> _fetchEventsFromFirestore() async {
  final QuerySnapshot snapshot = await FirebaseFirestore.instance.collection('event').get();
  return snapshot.docs
      .map((doc) => Meeting.fromMap(doc.data() as Map<String, dynamic>))
      .toList();
}

// 实时监听数据变化(适合数据更新后自动刷新日历的场景)
Stream<List<Meeting>> _streamEventsFromFirestore() {
  return FirebaseFirestore.instance.collection('event').snapshots().map((snapshot) {
    return snapshot.docs
        .map((doc) => Meeting.fromMap(doc.data() as Map<String, dynamic>))
        .toList();
  });
}

步骤3:用异步组件渲染SfCalendar

因为Firestore数据获取是异步操作,需要用FutureBuilder或StreamBuilder处理加载状态,并将数据传入EventDataSource:

方案A:一次性加载数据(FutureBuilder)

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: FutureBuilder<List<Meeting>>(
      future: _fetchEventsFromFirestore(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else if (snapshot.hasError) {
          return Center(child: Text('加载失败: ${snapshot.error}'));
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          return const Center(child: Text('暂无预约讲座'));
        } else {
          return SfCalendar(
            view: CalendarView.month,
            dataSource: EventDataSource(snapshot.data!),
            monthViewSettings: const MonthViewSettings(
              appointmentDisplayMode: MonthAppointmentDisplayMode.appointment,
              showAgenda: true,
            ),
          );
        }
      },
    ),
  );
}

方案B:实时监听数据更新(StreamBuilder)

@override
Widget build(BuildContext context) {
  return Scaffold(
    body: StreamBuilder<List<Meeting>>(
      stream: _streamEventsFromFirestore(),
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const Center(child: CircularProgressIndicator());
        } else if (snapshot.hasError) {
          return Center(child: Text('加载失败: ${snapshot.error}'));
        } else if (!snapshot.hasData || snapshot.data!.isEmpty) {
          return const Center(child: Text('暂无预约讲座'));
        } else {
          return SfCalendar(
            view: CalendarView.month,
            dataSource: EventDataSource(snapshot.data!),
            monthViewSettings: const MonthViewSettings(
              appointmentDisplayMode: MonthAppointmentDisplayMode.appointment,
              showAgenda: true,
            ),
          );
        }
      },
    ),
  );
}

注意事项

  • Firestore集合event的字段名必须和Meeting.fromMap中使用的字段一致,比如eventName、from(Timestamp类型)、to(Timestamp类型)、background(十六进制字符串)、isAllDay(布尔类型)。
  • 确保已正确配置Firebase项目,并且Firestore安全规则允许读取event集合(测试阶段可临时设置为允许所有读取,上线后需调整为符合业务逻辑的权限)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:25:23