⌚
dropdownボタンに現在時刻から日付を取得する
閏年にも対応できる
文字を直接書いて、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