【Flutter】Firebase×TableCalendarでイベントドットを表示

flutter

Firebaseのデータを呼んでカレンダー(table_calendar)にイベントドットを表示させたいと思いその備忘録をここに記載します。
特に初期起動時に表示させたいなと思った時の備忘録で状態管理には、flutter_hooksを使用しています。(2023.06現在)

アプリの見た目

使用したフレームワーク

-- ライブラリ
dependencies:
  flutter:
    sdk: flutter

  table_calendar: ^3.0.9
  flutter_hooks: ^0.18.6
  firebase_core: ^2.9.0
  cloud_firestore: ^4.5.1
-- flutterバージョン
Flutter 3.10.4 • channel stable • https://github.com/flutter/flutter.git
Tools • Dart 3.0.3 • DevTools 2.23.1

4つのポイント

今回は下記4つのポイントに絞って解説します。
今回フォーカスしない部分についての解説は省略します。(Firebaseの登録、イベント追加など)

  • イベントの表示
  • useEffectでの初期更新
  • Future関数
  • Firebaseのデータ読み込み

イベントの表示

table_calendarでイベントドット(言い回しが正しいかはわかりませんmm)を表示するにはeventLoaderを使用します。

TableCalendar(
 eventLoader: ,

今回は、useStateで宣言した変数(ev)に引数のdateをキーとして返しています。
こうすることで変数が更新されたらキーと一致したもを表示可能になります。

nullsafetyとして演算子でnullの場合、空のリストを返しています。

  final ev = useState({});               
  TableCalendar(
     eventLoader: (date) {
            return ev.value2024/03/29 ?? [];
                     },

hooksのuseStateの使い方については下記サイトが参考になりました。

Flutter HooksのuseXXXの使い方 - Qiita
はじめにFlutter HooksとはReact HooksのFlutter版です。React Hooksについてはこちらの記事がわかりやすいです。5分でわかるReact Hooks現在、Hooks自体が注目されている...

useEffectでの初期更新

useEffectを使用してStatefullWidgetのinitState的な初回のみ実施する機能を追加します。
Firebaseの呼び出し関数がFuture型のためgetEvent()と別の関数に切り出しています。

    useEffect((){
      getEvent(); //イベントを取得する関数
      return null;
    },const []);

Future関数

useEffectでFirebaseの呼び込みメソッドを初回だけ呼んで呼んできた値をuseStateのev変数に代入しています。

    Future getEvent() async {
      final eventList = await loadFirebaseData(DateTime.now()); // Firebaseを呼んでいる関数
      ev.value = eventList;
     return ev.value;
    }

async,awaitを使ってFuture関数をmap型に変換しています。
async,awaitの使い方は下記サイトが参考になります。

【Dart】Futureクラスとasync/awaitの基本的な使い方

Firebaseのデータ読み込み

最終的にFirebaseからデータを呼んでいるメソッドが以下です。
ネストが深くてもっと簡潔に書けるかもですが、すみませんmm。

static final firebaseEvents = FirebaseFirestore.instance.collection('自分が設定した名前');

 // 1ヶ月のデータ取得
  static loadFirebaseData(focusedDay) async {
     Map<DateTime, List<Event>> events = {};
     
    final snap = await firebaseEvents
        .withConverter(
        fromFirestore: (event, _) => Event.fromFirestore(event),
        toFirestore: (Event event, _) => event.toFirestore()
    ).get();

    for (var doc in snap.docs) {
      final event = doc.data();
      final _eventDay = event.eventDay.toDate();
      final day = DateTime.utc(_eventDay.year, _eventDay.month, _eventDay.day);

      if (events[day] == null) {
        events[day] = [];
      }

      events[day]!.add(event);
    }
    print('event: $events');
    return events;
  }

下記サイトを参考にFirebaseのイベント取得を実装しました。
withConverterなどを使用しているためちょっと複雑ですが、やっていることはシンプルです。

引数で呼ばれた日付より1ヶ月のデータをFirebaseから取得しています。

Flutter Calendar App Optimizing Query and Managing Events
In previous two parts we learned to setup calendar and load and display events from Firestore. In this third and final part in the series, we will optimize the ...

下記のようなEventクラスを別で用意してイベントとイベントの日を定義しています。
factorywithConverterの使い方は後日解説できればと思います。

//イベントクラス
class Event {
  final String event;
  final Timestamp eventDay;

  Event({required this.event, required this.eventDay});

  factory Event.fromFirestore(DocumentSnapshot<Map<String, dynamic>> snapshot,
      [SnapshotOptions? options]) {
    final data = snapshot.data()!;
    return Event(
      event: data['event'],
      eventDay: data['date'],
    );
  }

  Map<String, Object?> toFirestore() {
    return {
      "date": eventDay,
      "event": event
    };
  }
}

最後に

これで初回起動時にイベントドットを表示することが可能になりました。
もっといろんな角度からのやり方があると思いますのであくまで参考程度になればと思います。

私自身、理解を深めもっと簡潔にかつ有効な書き方を模索していきます。

ではまた。

コメント

タイトルとURLをコピーしました