【Flutter】syncfusion_flutter_datepicker 使ってみた！

# やりたかったこと
 * 特定の日に色をつけたり、わかりやすくしたい!
  * 複数日選択できる
  * 使い方簡単なやつ
  * デザインシンプル

![flut-3742_img1.jpeg]
(https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/873366/4b5aa2dc-e141-d346-9a52-acfdd6e26baa.jpeg)


カレンダーではよくある機能なのですが、予定がある日にアイコンをつけたり何かしら他の日と区別できるようにしたかったので、デフォルトのdatePicerではできることが限られていることから、簡単に使えそうで、デザインも良さげなこちらを使ってみることにしました！

[syncfusion_flutter_datepicker](https://pub.dev/packages/syncfusion_flutter_datepicker)

# 導入

```dart
// pubspec.yaml
syncfusion_flutter_datepicker: ^XX.X.X
```

まずは、簡単にダイアログに表示したい場合はこちらを書けばいいだけ！

```dart
  // controller
  final ScrollController _scrollController = ScrollController();
  -- 省略 --
  // ボタンを押したら表示！
  OutlinedButton(
    child: Text('日付を選択する'),
    onPressed: () async {
      // 下記のように返り値で取得するようにすればcontrollerはなくてもOK!
      final DateTime? selectedDate = await _selectDate(context, controller);
      // controllerから選択した日付を取得したい時
      if (controller.selectedDate != null) {
        // controller.selectedDate!で使えます！
    },
  );
  -- 省略 --

Future<DateTime?> _selectDate(BuildContext context, DateRangePickerController controller) async {

  await showDialog(
      context: context,
      builder: (_) {
        return SimpleDialog(
          contentPadding: EdgeInsets.all(0.0),
          titlePadding: EdgeInsets.all(0.0),
          title: Container(
            height: 400,
            child: Scaffold(
              body: Container(
                child: SfDateRangePicker(
                  // controllerは設定しなくてもOK!
                  // 他の項目も必要なものだけ設定してください。他にも色々あります。
                  controller: controller,
                    view: DateRangePickerView.month,
                    monthViewSettings: DateRangePickerMonthViewSettings(
                        specialDates: _specialDates, firstDayOfWeek: 1),
                    cellBuilder: cellBuilder, // デザインを変更したい場合。詳細はページ下部へ
                    initialSelectedDate: DateTime(2021,10,1), // 選択済みの日
                    // multiple 複数日
                    // range 連日
                    // multiRange 複数連日 などバリエーション豊かに選択範囲が設定できます！
                    selectionMode: DateRangePickerSelectionMode.single, // 1日のみ
                    allowViewNavigation: true, // 月移動矢印
                    navigationMode: DateRangePickerNavigationMode.snap, // スクロール量、止まる位置 snapは月毎にぴったり止まって切り替わる
                    showNavigationArrow: true,
                    onViewChanged: (DateRangePickerViewChangedArgs args) {
                      // 日付が選択されたらここで受け取りできます
                      // controllerでもできるよ！
                      var visibleDates = args.visibleDateRange;
                    },
                    showActionButtons: true, // 下のボタンを表示したい時
                    onSubmit: (Object value) {
                      Navigator.pop(context);
                      return value;
                    },
                    onCancel: () {
                      Navigator.pop(context);
                    },
                  ),
              ),
            ),
          ),
        );
      });
```
# 日本語化

```dart
// pubspec.yaml
syncfusion_flutter_datepicker: ^XX.X.X
  flutter_localizations: * 追加
    sdk: flutter         * 追加
```


```dart
// main.dart
return MaterialApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
      ],
      supportedLocales: [
        const Locale('ja'),
      ],
      locale: const Locale('ja'),
```
# 特定の日にアイコン表示

cellBuilderを設定すると、セルをカスタマイズすることができます。
ちょっとハマった部分なのですが、月や年表示の切り替えの際にも、日付のcellBuilderが適応されてしまい適切に表示されなくなってしまいました。
controllerを使って、月や年の表示も設定しました。

```dart
// 特定の日を仮で作成
final List<DateTime> _specialDates = <DateTime>[
    DateTime.now().add(Duration(days: 2)),
    DateTime.now().add(Duration(days: 3)),
    DateTime.now().add(Duration(days: 6)),
    DateTime.now().add(Duration(days: 7)),
    DateTime.now().add(Duration(days: -2)),
    DateTime.now().add(Duration(days: -3)),
    DateTime.now().add(Duration(days: -6)),
    DateTime.now().add(Duration(days: -7))
  ];

bool isSpecialDate(DateTime date) {
    for (int j = 0; j < _specialDates.length; j++) {
      if (date.year == _specialDates[j].year &&
          date.month == _specialDates[j].month &&
          date.day == _specialDates[j].day) {
        return true;
      }
    }
    return false;
  }

  Widget cellBuilder(BuildContext context, DateRangePickerCellDetails details) {
    DateTime _visibleDates = details.date;

    String text;
    // controller.viewで今何が表示されているか条件分岐
    switch (controller.view) {
      case DateRangePickerView.month:
        text = details.date.day.toString();
        break;
      case DateRangePickerView.year:
        text = '${details.date.month}月';
        break;
      case DateRangePickerView.decade:
        text = details.date.year.toString();
        break;
      default:
        final int yearValue = (details.date.year ~/ 10) * 10;
        text = yearValue.toString() + ' - ' + (yearValue + 9).toString();
        break;
    }
    // お好みでデザインを変更してみてください！結構色々設定できそうですーー
    if (isSpecialDate(_visibleDates)) {
      return Column(
        children: [
          Container(
            child: Text(
              details.date.day.toString(),
              textAlign: TextAlign.center,
            ),
          ),
          Divider(
            color: Colors.white,
            height: 5,
          ),
          Icon(
            Icons.celebration,
            size: 13,
            color: Colors.red,
          ),
        ],
      );
    } else {
      return Container(
        child: Text(
          text,
          textAlign: TextAlign.center,
        ),
      );
    }
  }
```
画像やサンプルコードもこちらを参考、拝借しています。
[syncfusion_flutter_datepicker](https://pub.dev/packages/syncfusion_flutter_datepicker)
[特別な日付をカスタマイズする方法]
(https://www.syncfusion.com/kb/12374/how-to-customize-the-special-dates-using-builder-in-the-flutter-date-range-picker)
[月セルのカスタマイズ]
(https://help.syncfusion.com/flutter/daterangepicker/customizations)
[PickerDateRangeについて]
(https://help.syncfusion.com/flutter/daterangepicker/callbacks)
[youtube]
(https://www.youtube.com/watch?v=3TyuUVExuPs&t=35s)