Be simple

”当たり前”が誰かのためになる

Flutterでライブラリを使ってカレンダーを実装する

はじめに

こんにちは

今日は、Flutterでカレンダー機能を実装するやり方について書き残しておきたいと思います。

今回作るサンプルはこちらです。

f:id:rozkey59:20190423181406g:plain

カレンダーのサンプル

 

この記事で触れている内容

  • Flutterでライブラリを使ってカレンダー機能を実装するまで

 

対象読者

  • Flutterをやっていて、カレンダー機能を実装したことがない人
  • アプリにカレンダーの機能を入れたいと考えている人

 

使用するライブラリ

今回使用するライブラリは次のとおりです。

github.com

カレンダーの機能をサクッと作ることができます。

作る前に、ライブラリにスターしましょう。

 

今回のサンプル

Flutterの実装Tipsをまとめるように、リポジトリを新たに作成しました。

今回のカレンダーに関しては、次のリポジトリのProject > lib > tips > calender_example.dartで全体のソースコードを見ることができます。

github.com

 

 

随時更新予定です。

 

それでは、まず開発前の準備からやっていきましょう。

 

開発前準備

Flutterのプロジェクトを作成していたら、pubspec.yamlがプロジェクト配下にあると思いますので、そちらに次のように追加してください。

dependencies:
flutter_calendar_carousel: ^1.3.16 // 追加

2019年4月現在、最新バージョンは1.3.16です。

 

yamlに追加したら、flutter package getをしましょう。

IDEAにPluginを入れていれば、下の画像の部分で、Package getをクリックするだけで良いです。

f:id:rozkey59:20190423145427p:plain

Flutter Package Get

これで、開発前準備は完了です。

それでは、実際に手を動かして作っていきましょう。

 

Flutterでライブラリを使ってカレンダー機能を実装するまで

まず、dartファイルをProject > lib配下に新しく作成してもらって、StatefulWidgetを継承したクラスを作成します。

自分の場合は、StatefulWidgetクラスを継承したCalenderExampleクラスを次のように作成しました。

先に示したリンクからもみれますが、コードの全容は次のとおりです。

import 'package:flutter/material.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:flutter_calendar_carousel/classes/event.dart';
import 'package:flutter_calendar_carousel/flutter_calendar_carousel.dart'
show CalendarCarousel;

class CalenderExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _CalenderExampleState();
}
}

class _CalenderExampleState extends State<CalenderExample> {
DateTime _currentDate = DateTime.now();

void onDayPressed(DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
Fluttertoast.showToast(msg: date.toString());
}

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Calender Example"),
),
body: Container(
child: CalendarCarousel<Event>(
onDayPressed: onDayPressed,
weekendTextStyle: TextStyle(color: Colors.red),
thisMonthDayBorderColor: Colors.grey,
weekFormat: false,
height: 420.0,
selectedDateTime: _currentDate,
daysHaveCircularBorder: false,
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDateShowIcon: true,
markedDateIconMaxShown: 2,
todayTextStyle: TextStyle(
color: Colors.blue,
),
markedDateIconBuilder: (event) {
return event.icon;
},
todayBorderColor: Colors.green,
markedDateMoreShowTotal: false),
));
}
}

 

flutter_calender_carouselライブラリを用いるには、最初にimportを適切に行なってください。次のように書きます。

 

import 'package:flutter_calendar_carousel/classes/event.dart';
import 'package:flutter_calendar_carousel/flutter_calendar_carousel.dart'
show CalendarCarousel;

これでimportは大丈夫です。

 

Carenderを作成するのに、いくつか項目をCalenderCarouselに設定する必要があります。独断と偏見で、多分これを知っておけば大体のことに対応できるんじゃないかなっと思ったものだけ紹介します。

 

まずは、onDayPressedについて

onDayPressedは、日付をタップした際の挙動を変えます。

コードは次のように書きます。

CalendarCarousel<Event>(
onDayPressed: onDayPressed,
)

onDayPressed関数を用意します。

DateTime _currentDate = DateTime.now();

void onDayPressed(DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
Fluttertoast.showToast(msg: date.toString());
}

サンプルではFlutterToastを利用してタップ時に、日付を表示するようにしています。

また、今日の日付を最初に設定しています。

 

FlutterToastは次の記事を参考にしてください。

qiita.com

 

次は、weekendTextStyleです。

CalendarCarousel<Event>(
weekendTextStyle: TextStyle(color: Colors.red),
)

名前の通り、土日のテキストのスタイルを指定できます。例えば、Colors.blueを指定すると次のようになります。

f:id:rozkey59:20190424163455p:plain

土日のテキストを青色に変更

次は、日付の枠に線を入れる、thisMonthDayBorderColorについてです

CalendarCarousel<Event>(
thisMonthDayBorderColor: Colors.grey,
)

冒頭の自分のサンプルでは、灰色の枠をつけたいので追加していますが、この項目を設定しないと枠線がつかないカレンダーを実装できます。枠線がつかない場合は次のとおりです。

f:id:rozkey59:20190424164019p:plain

枠線がつかない場合のカレンダーサンプル

 

次は、weekFormatについてです。

CalendarCarousel<Event>(
weekFormat: true,
)

defaultはfalseです。これは、週ごとに表示するかどうか選べます。trueにした場合は、次のようになります。

f:id:rozkey59:20190424164450p:plain

週ごとに表示した場合のサンプル

冒頭のサンプルのように、月ごとに表示したい場合にはfalseを指定するかこの項目を指定しないことで実現できます。

 

次は、selectedDateTimeです。

CalendarCarousel<Event>(
selectedDateTime: _currentDate,
)

これは、初回ビルド時にどの項目を選択しているか設定できます。サンプルで_currentDate = DateTime.now()で今日の日付を選択するようにしているので、冒頭のサンプルでは今日の日付が選択されています。

特になければ、今日の日付を入れましょう。

 

次は、 localです

CalendarCarousel<Event>(
locale: 'JA',
)

デフォルトの言語は、Englishなので英語表記になっていますが、日本語での指定もできます。localにJAと記載してあげることで、日本語のカレンダー表記に変わります。

この状態で実行すると次のようになります。

f:id:rozkey59:20190425003208p:plain

日本語表記のサンプル

年と月、それに曜日が日本語表記に変わっていることを確認できます。

 

次は、daysHaveCircularBorderです

CalendarCarousel<Event>(
daysHaveCircularBorder: true,
)

これは、枠線を丸にしてくれます。四角い枠線をつけたい場合は、falseを指定してthisMonthDayBorderColorを明示的に書きましょう。trueを指定して、thisMonthDayBorderColorを明示的に指定した場合は、次のようなレイアウトになります。

f:id:rozkey59:20190424165603p:plain

trueにして枠線の色を指定した場合のサンプル

この項目を設定しない場合は、次のようになります。

f:id:rozkey59:20190424165741p:plain

項目自体を設定しなかった時のサンプル

次は、customGridViewPhysicsです

CalendarCarousel<Event>(
customGridViewPhysics: NeverScrollableScrollPhysics(),
)

これは指定しないと、カレンダーのGridViewが縦にスクロールできるんですがカレンダーに縦スクロールを入れたくない場合には、NeverScrollableScrollPhysicsを入れるようにしてください。

複数のレイアウトと組み合わせて縦スクロールを入れたいけれど、カレンダー自体は縦スクロールの挙動を入れたくない時に使います。

 

CalenderCarouselの設定で重要なのは、多分これくらいです。

他に重要なものなどあれば後でまた補足という形で追加していきます。

 

次は、Eventについてです。

Eventについて

Eventはカレンダーに予定を作成などした時に設定する項目になります。

カレンダーをタップした際に例えば予定など作成した後に、その予定が入っている日に何かしらマーカーとして画像などを表示したい時に利用します。

 

今回は、例としてタップした初回にアイコンを表示するようにし、もう一度そのアイコンをタップすると日付がトーストとして出るようにします。

紹介するサンプルのgifが次のとおりです。

f:id:rozkey59:20190424173445g:plain

Eventのサンプル

 

サンプルのコードは次のとおりです。

class CalenderExample extends StatefulWidget {
@override
State<StatefulWidget> createState() {
return _CalenderExampleState();
}
}

class _CalenderExampleState extends State<CalenderExample> {
DateTime _currentDate = DateTime.now();
EventList<Event> _markedDateMap = EventList<Event>(); // 追加

void onDayPressed(DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
if (events.length == 0) {
Fluttertoast.showToast(msg: date.toString());
addEvent(date);
} else {
Fluttertoast.showToast(msg: events[0].title);
} // 追加
// addEvent(date);
}

void addEvent(DateTime date) {
_markedDateMap.add(date, createEvent(date));
} // 追加

Event createEvent(DateTime date) {
return Event(
date: date,
title: date.day.toString(),
icon: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blue, width: 1.0)),
child: Icon(
Icons.calendar_today,
color: Colors.blue,
)
)
);
} // 追加

@override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Calender Example"),
),
body: Container(
child: CalendarCarousel<Event>(
onDayPressed: onDayPressed,
weekendTextStyle: TextStyle(color: Colors.red),
thisMonthDayBorderColor: Colors.grey,
weekFormat: false,
height: 420.0,
selectedDateTime: _currentDate,
daysHaveCircularBorder: false,
customGridViewPhysics: NeverScrollableScrollPhysics(),
markedDatesMap: _markedDateMap, // 追加
markedDateShowIcon: true,
markedDateIconMaxShown: 2,
todayTextStyle: TextStyle(
color: Colors.blue,
),
markedDateIconBuilder: (event) {
return event.icon;
},
todayBorderColor: Colors.green,
markedDateMoreShowTotal: false),
));
}
}

 

 まずはじめに、Eventを設定するために、メンバにEventのからのリストを持たせます

EventList<Event> _markedDateMap = EventList<Event>();

 そしたら、CalenderCarouselに次のように設定します。

CalendarCarousel<Event>(
markedDatesMap: _markedDateMap,
)

次は、カレンダーに表示するアイコンのレイアウトを作成します。

わかりやすいようにEventを返す、createEvent関数を次のように作りました。

Event createEvent(DateTime date) {
return Event(
date: date,
title: date.day.toString(),
icon: Container(
decoration: BoxDecoration(
color: Colors.white,
border: Border.all(color: Colors.blue, width: 1.0)),
child: Icon(
Icons.calendar_today,
color: Colors.blue,
)
)
);
}

Eventには引数が3つあって、dateはEventを作りたい(予定を作りたい)日のDateTime、titleはタップした時にトーストに表示するための文字列(なんでも良いが今回は日にちを入れている)、iconには任意のWidgetを設定します。

自分はiconを四角くした線入りの枠の中にカレンダーアイコンを入れて表示するようにしています。

 

次に、この作成したEventを先ほどの_markedDateMapのリストに追加していきます。

今回は、タップした際に追加するようにしているので、次のようにコードを書きました。

void onDayPressed(DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
if (events.length == 0) {
Fluttertoast.showToast(msg: date.toString());
addEvent(date);
} else {
Fluttertoast.showToast(msg: events[0].title);
}
// addEvent(date);
}

void addEvent(DateTime date) {
_markedDateMap.add(date, createEvent(date));
}

上で紹介したonDayPressedのなかで、まだカレンダー上にEventが作成されていなければEventListにaddするようにしています。

ここまで書くとgifのような挙動を実現できます。

 

また、複数の予定を作成した場合はonDayPressedのコードを次のように書き換えると動作をテスト的に確認できます。

  void onDayPressed(DateTime date, List<Event> events) {
this.setState(() => _currentDate = date);
// if (events.length == 0) {
// Fluttertoast.showToast(msg: date.toString());
// addEvent(date);
// } else {
// Fluttertoast.showToast(msg: events[0].title);
// }
addEvent(date);
}

このコードを実行すると次のような挙動に変わります。

f:id:rozkey59:20190424174519g:plain

複数の予定を作成した場合

EventListに対してEventをaddしていくだけで、カウント表示までライブラリ側がやってくれます。とても便利ですね。

 

以上で、Flutterでライブラリを使ってカレンダー機能を実装するまでの紹介でした。

 

おわりに

今回は、Flutterでカレンダー機能を実装するまでを紹介いたしました。

もし、不明点やこうやったほうがいいなど指摘事項があれば、コメントしていただけると嬉しいです。

 

また、ライブラリ作成者は時間をかけて良いものを作ってくれているので、もしよければスターをしてあげてください。ボタンを押すだけでできます。

 

不定期ですが、今後もこういったTipsをまとめていこうと思います。

それでは、またの機会に。