kazpgmの日記

『プログラム自動作成@自動生成』作成の日記

フロント側をFlutter(スマホ)Thymeleaf(PC)、バックエンド側SpringBootの自動作成勉強中

9:45
①今日は、Flutterでの日付のダイヤログ入力を調査する。(ダイヤログ画面じゃないと、共通的に使う時、使い勝手がわるいので)
 まずはtable_calendarとintlパッケージをインストールした。
 pubspec.yaml

 dependencies:
  flutter:
    sdk: flutter
  table_calendar: ^3.0.5
  intl: ^0.17.0

を追加して、pub getを実行。

20:18
①まだまだ、だけど、こんなところまででできた。
途中、
②Locale data has not been initialized, call initializeDateFormatting(). というエラーが出た。調べたところ「DateFormat('yyyy/MM/dd');」を使う前に「initializeDateFormatting('ja', null);」をやっておかなくてはいけないらしい。
更にimportを「import 'package:intl/date_symbol_data_local.dart'; 」にしないといけない。
③日付ダイアログはできたが、日を押してもその日に色がつかない。理由は、setStateが使えないからだった。
そこで、NETで調べた。結果、以下を修正して動いた。
 ・SimpleDialogクラスがStatelessWidgetであるため、setStateできていないようです。
 ・StatelessWidgetをStatefulWidgetとして扱うためには、『StatefulBuilder』ウィジェットを使うらしい。

20:55
①ここで、今できている画面遷移を載せておこう。詳細は明日また考えるとして。
テストとして日付項目を作ってテストした。

日付選択ボタン押下で、日付のダイヤログ画面を表示する。

2020年1月を表示して、1月1日に赤丸”祝"がついている(イベントを使って表示している)ことを確認した。
さらに、1月7日を選択して色がつくことを確認した。

OK押下で選択した1月7日が反映したことを確認した。

②Flutterプログラム
■画面.dartに以下を追加した

  String _focusedDayStr="";
    //--テスト日付入力 start----------------------------
    contentWidgets.add(
      Row (
//      mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          // テスト日付の入力フォーム
          Container(
            margin: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 5),
            padding: const EdgeInsets.fromLTRB(10.0, 0, 10.0, 0),
            child:Text(_focusedDayStr,
              textAlign: TextAlign.left,
              overflow: TextOverflow.clip,
            ),
          ),
          Container(
            margin: const EdgeInsets.fromLTRB(5, 0, 5, 5),
            padding: const EdgeInsets.fromLTRB(5, 0, 5, 0),
            child: ElevatedButton(
              onPressed: () async {
                String? _str = await CommUtils.openDateDialogComm(context, '日付選択', DateTime.now());
                if (_str != Consts.cancel) {
                  setState(() {
                    _focusedDayStr = _str!;
                  });
                }
              },
              style: ElevatedButton.styleFrom(
                primary: Colors.blue,
              ),
              child: const Text("日付選択"),
            ),
          ),
        ]
      ),
    );
    //--テスト日付入力 end----------------------------

■CommUtilsクラスに以下を追加した

  /// 日付入力ダイヤログ
  /// 選択日付、CANCELを戻す。
  static Future<String?> openDateDialogComm(BuildContext context, String msg, DateTime _focusedDay) async {
    initializeDateFormatting('ja', null);
    DateFormat outputFormat = DateFormat('yyyy/MM/dd');
    DateTime? _selectedDay;
    // 祝祭日リスト
    Map<DateTime, List> _eventsList = {
      DateTime(2022, 1, 1, 0, 0): ['祝'],
    };
    int getHashCode(DateTime key) {
      return key.day * 1000000 + key.month * 10000 + key.year;
    }
    // TableCalendarでは、カレンダーに読み込むイベントをMapで定義した場合、
    // LinkedHashMap使用が推奨されている。
    final _events = LinkedHashMap<DateTime, List>(
      equals: isSameDay,
      hashCode: getHashCode,
    )..addAll(_eventsList);
    List getEventForDay(DateTime day) {
      return _events[day] ?? [];
    }
    var result  = await showDialog<String>(
      context: context,
      barrierDismissible: false,
      builder: (BuildContext context) {
        return StatefulBuilder(
          builder: (context, setState) {
            return SimpleDialog(
              title: Text(msg),
              children: <Widget>[
                TableCalendar(
                  locale: 'ja',
                  // カレンダーの最初と最後の月を設定
                  firstDay: DateTime.utc(1950, 1, 1),
                  lastDay: DateTime.utc(2050, 12, 31),
                  // focusedDayによって日付に印がつく
                  focusedDay: _focusedDay,
                  // イベントを読み込む。祝日に赤丸”祝”を表示
                  eventLoader: getEventForDay,
                  // カレンダーフォーマットを月単位とする
                  calendarFormat: CalendarFormat.month,
                  // カレンダーフォーマット変更ボタンを表示しない
                  headerStyle: const HeaderStyle(
                    formatButtonVisible: false,
                  ),
                  // どの日が現在選択されているかを判断する。
                  // dayが選択されたら、trueを返す。
                  selectedDayPredicate: (day) {
                    return isSameDay(_selectedDay, day);
                  },
                  // 選択した日付を一時的に保存し、selectedDayPredicateオプションで
                  // 保存された日付情報にフォーカスを当てて印が付けている。
                  onDaySelected: (selectedDay, focusedDay) {
                    if (!isSameDay(_selectedDay, selectedDay)) {
                      setState(() {
                        _selectedDay = selectedDay;
                        _focusedDay = focusedDay;
                      });
                    }
                  },
                  onPageChanged: (focusedDay) {
                    _focusedDay = focusedDay;
                  },
                  calendarBuilders: CalendarBuilders(
                    // イベントマーカーをmarkerBuilderを使用してカスタマイズする
                    markerBuilder: (context, date, events) {
                      if (events.isNotEmpty) {
                        return _buildEventsMarker(date, events);
                      }
                    },
                  ),
                ),
                SimpleDialogOption(child: const Text('OK'), onPressed: () {
                  // 選択した日付を戻す
                  Navigator.pop(context, _selectedDay==null?Consts.cancel:outputFormat.format(_selectedDay!));
                },),
                SimpleDialogOption(child: const Text('キャンセル'), onPressed: () {
                  // ”cancel”を戻す
                  Navigator.pop(context, Consts.cancel);
                },)
              ],
            );
          }
        );
      },
    );
    return result;
  }

  // 日付入力ダイヤログ
  // イベントマーカーを赤丸”祝”とする
  static Widget _buildEventsMarker(DateTime date, List events) {
    return Positioned(
      right: 5,
      bottom: 5,
      child: AnimatedContainer(
        duration: const Duration(milliseconds: 300),
        decoration: BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.red[300],
        ),
        width: 16.0,
        height: 16.0,
        child: Center(
          child: Text(
            '祝',
            style: const TextStyle().copyWith(
              color: Colors.white,
              fontSize: 12.0,
            ),
          ),
        ),
      ),
    );
  }

■2022/06/15に、勉強した成果:『Flutter_JavaSpringプログラム自動作成◎自動生成ツール』をVectorに載せました。Zenn本も書きました。使ってみての感想や間違いの指定や、こうやったほうがいいとかの情報があればメールください。
Vector
www.vector.co.jp
・Zenn本(Flutter_JavaSpringプログラム自動作成)
zenn.dev