【Flutter】table_calendariを使用してiOS・Androidアプリのカレンダー作成

Flutterアプリ

Flutterでカレンダーを使用してアプリを作る際に便利なパッケージとしてTableCalendarがあります。

今回は、Flutterでカレンダーを作成するのに王道なtable_calendarを使った実装を解説していきたいと思います。(2023.02現在)


今回使用したバージョンは下記の通りです。

Flutter 3.0.5
Dart 2.17.6 
table_calendar: 3.0.9

対象の読書

  • FlutterでTableCalendarを使用してアプリを作りたい人
  • TableCalendarの基本的な使い方を知りたい人

パッケージのインストール

まずは、どのパッケージでもお馴染みのpubspec.yamlファイルに設定を書き込みんで「flutter pub get」コマンドを実行します。

environment:
  sdk: ">=2.17.6 <3.0.0"


dependencies:
  flutter:
    sdk: flutter
  table_calendar: ^3.0.9

カレンダーの表示

まずはシンプルなカレンダーを表示します。
以下の実装でカレンダーの表示が可能です。

focesedDayは今日に日付に印がつきます。

DateTime _focusedDay = DateTime.now();

TableCalendar(
  firstDay: DateTime.utc(2023, 1, 1),
  lastDay: DateTime.utc(2024, 12, 31),
  focusedDay: _focusedDay,
);

カレンダーフォーマット

次にカレンダーの表示を「1週間、2週間、1ヶ月」と3つに変更できるように実装します。
デフォルトを1ヶ月の表示に設定しています。

CalendarFormat _calendarFormat = CalendarFormat.month; // 月フォーマット               

onFormatChanged: (format) {  // 「月」「週」変更
                  if (_calendarFormat != format) {
                    setState(() {
                      _calendarFormat = format;
                    });
                  }
                }

日付の選択

selectedDayPredicate:を使用してどの日が現在選択されているかを設定します。
今回はisSameDay関数を返す実装にしています。
isSameDayは2つの引数(DateTime)を取り、2つの日付が同じか否かを判定します。

DateTime? _selectedDay; // 選択している日付 

          // 選択日のアニメーション
                selectedDayPredicate: (day) {
              return isSameDay(_selectedDay, day);
            },

加えてももう一つ下記の実装が必要になります。

                // 日付が選択されたときの処理
                onDaySelected: (selectedDay, focusedDay) {
                  setState(() {
                    _selectedDay = selectedDay;
                    _focusedDay = focusedDay;
                  });
                }

onDaySelected カレンダーがタップされるたびに呼ばれる関数で、そこにタップした際の日付(_selectedDay)を設定します。

イベントドットの表示

ここからは少しだけ応用です。
自分がドットマークをつけたい日付を宣言し、eventLoaderに返してあげればドットが表示されます。

  //Map形式で保持 keyが日付 値が文字列
  final sampleMap = {
    DateTime.utc(2023, 2,20): ['firstEvent', 'secondEvent'],
    DateTime.utc(2023, 2,5): ['thirdEvent', 'fourthEvent'],
  };

  eventLoader: (date) { // イベントドット処理
     return sampleMap2024/11/10 ?? []
         },

イベントの表示

さらにイベントをTextなどに表示したい場合も少し触れます。
Textなどに表示したい日付を宣言し_selectedEventsに代入してあげれば可能です。

List<String> _selectedEvents = []; 

 final sampleEvents = {
    DateTime.utc(2023, 2,20): ['firstEvent', 'secondEvent'],
    DateTime.utc(2023, 2,5): ['thirdEvent', 'fourthEvent']
  };


                // 日付が選択されたときの処理
                onDaySelected: (selectedDay, focusedDay) {
                  setState(() {
                    _selectedDay = selectedDay;
                    _focusedDay = focusedDay;
                    _selectedEvents = sampleEvents[selectedDay] ?? []; // ココを追加
                  });
                }

あとは、_selectedEventsに格納されたものを好きなものに表示させればOKです。
今回はListTileに表示させます。

          // タップした時表示するリスト
          Expanded(
            child: ListView.builder(
              itemCount: _selectedEvents.length,
              itemBuilder: (context, index) {
                final event = _selectedEvents[index];
                return Card(
                  child: ListTile(
                    title: Text(event),
                  ),
                );
              },
            ),
          ),

全体のコード

全体のコードはこちらになります。

import 'dart:collection';

import 'package:flutter/material.dart';
import 'package:table_calendar/table_calendar.dart';

class CalenderPage extends StatefulWidget {
  const CalenderPage({Key? key}) : super(key: key);

  @override
  State<CalenderPage> createState() => _CalenderPageState();
}

class _CalenderPageState extends State<CalenderPage> {
  DateTime _focusedDay = DateTime.now(); // 現在日
  CalendarFormat _calendarFormat = CalendarFormat.month; // 月フォーマット
  DateTime? _selectedDay; // 選択している日付
  List<String> _selectedEvents = [];

  //Map形式で保持 keyが日付 値が文字列
  final sampleMap = {
    DateTime.utc(2023, 2,20): ['firstEvent', 'secondEvent'],
    DateTime.utc(2023, 2,5): ['thirdEvent', 'fourthEvent'],
  };

  final sampleEvents = {
    DateTime.utc(2023, 2,20): ['firstEvent', 'secondEvent'],
    DateTime.utc(2023, 2,5): ['thirdEvent', 'fourthEvent']
  };

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // カレンダーUI実装
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(20.0),
            child: TableCalendar(
                firstDay: DateTime.utc(2023, 1, 1),
                lastDay: DateTime.utc(2024, 12, 31),
                focusedDay: _focusedDay,
                eventLoader: (date) { // イベントドット処理
                  return sampleMap2024/11/10 ?? [];
                },
                calendarFormat: _calendarFormat, // デフォを月表示に設定
                onFormatChanged: (format) {  // 「月」「週」変更
                  if (_calendarFormat != format) {
                    setState(() {
                      _calendarFormat = format;
                    });
                  }
                },
                // 選択日のアニメーション
                selectedDayPredicate: (day) {
              return isSameDay(_selectedDay, day);
            },
                // 日付が選択されたときの処理
                onDaySelected: (selectedDay, focusedDay) {
                  setState(() {
                    _selectedDay = selectedDay;
                    _focusedDay = focusedDay;
                    _selectedEvents = sampleEvents[selectedDay] ?? [];
                  });
                }
                ),
          ),
          // タップした時表示するリスト
          Expanded(
            child: ListView.builder(
              itemCount: _selectedEvents.length,
              itemBuilder: (context, index) {
                final event = _selectedEvents[index];
                return Card(
                  child: ListTile(
                    title: Text(event),
                  ),
                );
              },
            ),
          ),
        ],
      ),
    );
  }
}

公式パッケージ

なるべく最新のものを使用する方がベターだと思います。

table_calendar | Flutter package
Highly customizable, feature-packed calendar widget for Flutter.

最後に

シンプルなカレンダーをtable_calendarを使用して実装してみました。
他にもいろんな機能があるのでぜひ試してみてください。

どなたかのご参考になれば幸いです。
ではまた。

コメント

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