📆
FlutterのTableCalendarのselectedDay
個人開発でモバイルアプリを作る中で、ふーんと思ったことを記録。
概要
- TableCalendarの
onDaySelected
コールバックの引数であるselectedDay
は、
yyyy-MM-DD 00:00:00Z
のように、選択した日が始まる時間(UTC)のDateTime
になっているっぽい。
やろうとしたこと
環境
- Flutter 3.13.6
- Dart 3.1.3
- table_calendar 3.1.3
内容
- 日記的なアプリで、カレンダーから日付を選択し、その日のエントリを追加する機能の実装
- カレンダーから日付を選択し、その日のエントリ一覧を表示する機能の実装
問題のあったコード
詳細は省略しますが、_selectedDate
を利用して選択した日の日記エントリを作成したり、選択した
日のエントリ一覧を取得して表示したりします。
カレンダーを一度も触っていない状態だと、_selectedDate
にはlocaltimeの日時が入っているため、ちょうど_selectedDate
に作成したエントリ(そんなものはない)しか表示されないという問題が発生しました。
(クエリを範囲指定にすればいいだけだった)
カレンダーを一度でも触ると、_selectedDate
にはutcかつ00:00:00の値が入るので、作成したエントリには揃えられた日時が登録され、エントリの取得時に時間がずれて参照できなくなるということはありませんでした。
class _DiaryState extends State<Diary> {
DateTime _selectedDate = DateTime.now();
// 省略
Widget build(BuildContext context) {
// 省略
TableCalendar(
headerStyle: const HeaderStyle(
formatButtonVisible: false,
),
focusedDay: _selectedDate,
firstDay: DateTime(2000),
lastDay: DateTime(2100),
calendarFormat: CalendarFormat.month,
selectedDayPredicate: (day) => isSameDay(_selectedDate, day),
onDaySelected: (selectedDay, focusedDay) {
setState(() {
_selectedDate = selectedDay;
});
},
),
// 省略
}
}
対応
今回、日記エントリには時間データは持たせず、日付だけを持たせるつもりでした。
日記エントリのモデルクラス側でフォーマットを調整することを考えましたが、TableCalendarのisSameDay
メソッドの判定基準とかもまだよくわかっていないので、全部TableCalendarに合わせて00:00:00(utc)にすることで解決😇
class _DiaryState extends State<Diary> {
DateTime _selectedDate = DateTime.now();
_DiaryState() {
// NOTE: TableCalendarのselectedDayはUTCの00:00:00なので、タイムゾーンを考慮して調整
_selectedDate = DateTime(_selectedDate.year, _selectedDate.month, _selectedDate.day);
Duration offset = _selectedDate.timeZoneOffset;
_selectedDate = _selectedDate.add(offset).toUtc();
}
// 省略
}
おわり
TableCalendarはデザインがシンプルで気に入りました。
参考
Discussion