【Flutter】 table_calendarをカスタムして当日に戻るボタンを作成。


## はじめに
Flutterでカレンダーを表示したいときによく使うのが`table_calendar`かと思います。
ただ、月を移動した後今日の日付に戻るためには、移動した月分操作しなければならず、少しめんどくさく感じるためUIをカスタムし当日へ戻るボタンをつけました。（ドキュメントで探しましたが、ないはず…あったらすみません…）

## まずカレンダーを準備
サッとtabel_calendar を準備します。この辺は[pub.dev](https://pub.dev/packages/table_calendar)に載ってるので簡潔に。
```
$ flutter pub add table_calendar
```

とりあえず始まりと最後を現在から前後2ヶ月に設定。
```
final _today = Datetime.now();
final _firstDay = DateTime(today.year, today.month - 2, 1);
final _lastDay = DateTime(today.year, today.month + 3, 0);

DateTime _focusedDay = _today;
```

カレンダーのウィジェットを作成。
```
TableCalendar(
  locale: 'ja_JP',
  firstDay: _firstDay,
  lastDay: _lastDay,
  focusedDay: _focusedDay,
  // この設定で月を移動した時にヘッダーの表示が移動先の月になる 
  onPageChanged: (focusedDay) {
    _focusedDay = focusedDay;
  }
  // 月曜日始まりにしたいときは入れる
  startDayOfWeek: StartingDayOfWeek.monday,
)
```

## Headerのカスタム 
table_calendarのUIをカスタムできる`calendarBuilders`を使用します。
```
TableCalendar(
  locale: 'ja_JP',
  firstDay: _firstDay,
  lastDay: _lastDay,
  focusedDay: _focusedDay,
  onPageChanged: (focusedDay) {
    _focusedDay = focusedDay;
  }
  startingDayOfWeek: StartingDayOfWeek.monday,
  // 以下からカスタム内容
  calendarBuilders: CalendarBuilders(
    // headerのカスタム
    headerTitleBuilder: (_, day) {
      final DateFormat dateFormat = DateFormat('yyyy年M月');
      return Row(
        mainAxisAlignment: MainAxisAlignment.spaceAround,
        children: [
          Text(dateFormat.format(_focusedDay), style: const TextStyle(fontSize: 16)),
          TextButton(
            onPressed: () {
              setState(() {
                _focusedDay = DateTime.now();
              })
            },
            child: const Text('今日')
          )
        ]
      );
    }
  )
)
```

ヘッダー部分のカスタムは、`headerTitleBulder`を使用します。
デフォルトのヘッダーのスタイルを踏襲して`yyyy年M月`の形にしています。
Text部分は`_focusedDay`を入れることで、先月や来月に移動した際、表示を移動した先の月に変更できます。
横並びでTextButton を配置し、タップしたら`_focusedDay`を今日に変更します。

これで当日に戻る機能が実装されました。

![calendar.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/6bbf0271-cf79-b516-8413-8cc1a7076567.gif)



## おまけ
### 見やすいように土日の色を変える
デフォルトでは曜日が全部灰色ですが、指定した曜日だけ色を変更できたりもします。
```
calendarBuilders: CalendarBuilders(
  headerTitleBuilder: (_, day) {  
  final DateFormat dateFormatForMonth = DateFormat('yyyy年M月');  
  return Row(  
    mainAxisAlignment: MainAxisAlignment.spaceAround,  
    children: [  
      Text(dateFormatForMonth.format(_focusedDay), style: const TextStyle(fontSize: 16),),  
      TextButton(  
          onPressed: () {  
            setState(() {  
              _selectedDay = DateTime.now();  
              _focusedDay = DateTime.now();  
            });  
          },  
          child: const Text('今日')  
      ),  
    ],  
  );  
},
// 以下追加。土日だけ色を変更する。
    dowBuilder: (_, day) {  
  final text = DateFormat.E('ja').format(day);  
  if (day.weekday == DateTime.sunday) {  
    return Center(  
      child: Text(text, style: const TextStyle(color: Colors.red, fontWeight: FontWeight.bold)),  
    );  
  } else if (day.weekday == DateTime.saturday) {  
    return Center(  
      child: Text(  
        text,  
        style: const TextStyle(color: Colors.blue, fontWeight: FontWeight.bold),  
      ),  
    );  
  }  
  return null;  
})

```

![スクリーンショット 2024-04-09 18.02.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669888/5f0ef280-d716-354b-5be4-a0661fea8cc5.png)