dropdownボタンに現在時刻から日付を取得する

2023/07/26に公開

閏年にも対応できる

文字を直接書いて、1~31日を指定したが、DateTimeで現在日時を取得して、1月だと31日まであって、2月だと28日の日付が変わるのに対応できる。
閏年だと、2月は29日まであるそうなんですよね。

本当にできるのか検証してみた?

まずは、状態を管理するクラスを作る。Notifier使いたかったがエラー出てくるので、StateNotifierを使った。Riverpod2.0では非推奨だそうですが、まだ使われているのをよく見かける気がする。

time.dart
import 'package:hooks_riverpod/hooks_riverpod.dart';

// StateNotifierで書いた例
class DayNotifier extends StateNotifier<int?> {
  DayNotifier() : super(null);
  // selectDayメソッドは、StateNotifierのstateを更新する
  void selectDay(int? day) {
    state = day;
  }
}

final dayProvider = StateNotifierProvider<DayNotifier, int?>((ref) {
  // 今日の日付を取得して、その月の日数を取得する
  var now = DateTime.now();
  // 月の日数を取得するには、次の月の0日目を取得する
  var daysInMonth = DateTime(now.year, now.month + 1, 0).day;
  // 月の日数分のリストを作成する。 .. は、前の行の結果を返す
  return DayNotifier()..selectDay(daysInMonth);
});

現在日時を表示するdropdownを使う

これ、本当にできるのかと思ったが意外とできました。状態の管理がされているので、ボタンを切り替えても日付が切り替わる。状態の更新がされないと、dropdownに値が表示されないので、結構ハマりました。

myapp.dart
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:widget_cheetsheet/time/time.dart';

class MyApp extends ConsumerWidget {
  
  Widget build(BuildContext context, WidgetRef ref) {
    // 今日の日付を取得して、その月の日数を取得する
    var now = DateTime.now();
    // 月の日数を取得するには、次の月の0日目を取得する
    var daysInMonth = DateTime(now.year, now.month + 1, 0).day;
    var days = List<int>.generate(daysInMonth, (index) => index + 1);

    final selectedDay = ref.watch(dayProvider);

    return Scaffold(
      appBar: AppBar(
        title: Text('Date Dropdown Button'),
      ),
      body: Center(
        // DropdownButtonは、選択肢のリストから1つを選択するためのウィジェット
        child: DropdownButton<int>(
          // valueは、選択された値を保持する
          value: selectedDay,
          // itemsは、選択肢のリスト
          items: days.map((int value) {// mapは、リストの各要素に対して処理を行う
            return DropdownMenuItem<int>(// DropdownMenuItemは、選択肢の1つを表す
              value: value,// valueは、選択肢の値
              child: Text(value.toString()),// childは、選択肢の表示内容
            );
          }).toList(),
          hint: Text('Select day'),
          onChanged: (int? newValue) {// onChangedは、選択肢が変更されたときに呼ばれる
            ref.read(dayProvider.notifier).selectDay(newValue);// selectDayメソッドは、StateNotifierのstateを更新する
          },
        ),
      ),
    );
  }
}

main.dartのコード
MyAppをimportして、ビルドする。

main.dart
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:widget_cheetsheet/time/myapp.dart';

void main() {
  runApp(const ProviderScope(child: App()));
}

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Date Dropdown Button',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyApp()
    );
  }
}

こんな感じでできました!

まとめ

StatefulWidgetでやったパターンもご紹介しておきます。なんでもRiverpodでやるかと言ったらそうではない場合もあったりします。皆さんも試してみてください。

import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int? daySelected;
  List<int> days = [];

  
  void initState() {
    super.initState();
    var now = DateTime.now();
    var daysInMonth = DateTime(now.year, now.month + 1, 0).day;
    days = List<int>.generate(daysInMonth, (index) => index + 1);
  }

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Date Dropdown Button'),
      ),
      body: Center(
        child: DropdownButton<int>(
          value: daySelected,
          items: days.map((int value) {
            return DropdownMenuItem<int>(
              value: value,
              child: Text(value.toString()),
            );
          }).toList(),
          hint: Text('Select day'),
          onChanged: (int? newValue) {
            setState(() {
              daySelected = newValue;
              print(daySelected);
            });
          },
        ),
      ),
    );
  }
}

Discussion