[Flutter] DatePicker

2023-03-18 hit count image

Flutterアプリでユーザが日付を入力する時カレンダー(DatePicker)を表示して日付を入れるようにする方法について説明します。

概要

アプリでユーザから日付を入力してもらうため、次のようにカレンダー(DatePicker)を表示するUIをよく見ます。

Flutter showDatePicker - DatePicker

今回のブログポストではshowDatePickerを使ってFlutterDatePickerを表示する方法について説明します。

ここで紹介するソースコードはGitHubで確認できます。

プロジェクト準備

showDatePickerの使い方を確認するため、次のようにボタンを表示する簡単なアプリを作ってみます。

Flutter showDatePicker - button for showDatePicker

次のコマンドを実行して新しいFlutterプロジェクトを生成します。

flutter create show_date_picker

新しいFlutterプロジェクトが生成されたら、main.dartファイルを開いて下記のように修正します。

class _MyHomePageState extends State<MyHomePage> {
  DateTime date = DateTime.now();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Date Picker Example'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {},
          child: Text(
            "${date.year.toString()}-${date.month.toString().padLeft(2, '0')}-${date.day.toString().padLeft(2, '0')}",
          ),
        ),
      ),
    );
  }
}

DatePickerを使ってボタンに表示される日付を変更する予定なので、Statefulウィジェットで生成しました。このようにmain.dartファイルを修正して保存すると、下記のようにボタンがうまく表示されることが確認できます。

Flutter showDatePicker - button for showDatePicker

今はボタンイベントに何もコードを追加してないので、ボタンを押しても何の動作もしないことが確認できます。

showDatePicker

次は、showDatePickerを使ってDatePickerを表示する方法についてみてみます。ボタンを押した時、showDatePickerを表示するためElevatedButtonウィジェットのonPressed関数を下記のように修正します。

...
ElevatedButton(
  onPressed: () async {
    final selectedDate = await showDatePicker(
      context: context,
      initialDate: date,
      firstDate: DateTime(2000),
      lastDate: DateTime.now(),
    );
    if (selectedDate != null) {
      setState(() {
        date = selectedDate;
      });
    }
  },
  ...,
),
...

showDatePicker関数はFuture<DateTime?>タイプを返すので、async-awaitを使う必要があります。また、ユーザが日付を選択しない場合、nullが帰ってくるので、ユーザが選択した日付を保存するためif文を使いました。最後に、ユーザが選択した日付をsetStateを使ってStateを変更して、画面をアップデートするようにしました。

このようにコードを修正して保存すると、次のようにボタンがまだうまく表示されることが確認できます。

Flutter showDatePicker - button for showDatePicker

そしたら、ボタンを押してみます。ボタンを押したら以前と違って次のようにカレンダーが表示されることが確認できます。

Flutter showDatePicker - DatePicker

次はカレンダーで好きな日付を押すと、次のようにボタンの日付がうまく変更されることが確認できます。

Flutter showDatePicker - change date by DatePicker

initialEntryMode

現在表示されたDatePickerの右上にある修正アイコンを押すと次のように日付を直接入力する画面が確認されます。

Flutter showDatePicker - edit date mode by DatePicker

この機能を使えないようにするためには、次のようにshowDatePicker関数のinitialEntryModeオプションにDatePickerEntryMode.calendarOnlyを設定する必要があります。

...
ElevatedButton(
  onPressed: () async {
    final selectedDate = await showDatePicker(
      context: context,
      initialDate: date,
      firstDate: DateTime(2000),
      lastDate: DateTime.now(),
      initialEntryMode: DatePickerEntryMode.calendarOnly,
    );
    if (selectedDate != null) {
      setState(() {
        date = selectedDate;
      });
    }
  },
  ...,
),
...

そしたら次のように右上に表示された修正アイコンが消えることが確認できます。

Flutter showDatePicker - disable edit date mode by DatePicker

多言語

カレンダーに表示される言語を英語ではなく他の言語で表示するためにはflutter_localizationsパッケージをインストールする必要があります。次のコマンドを使ってflutter_localizationsパッケージをインストールします。

flutter pub add flutter_localizations --sdk=flutter

または、pubspec.yamlファイルを次のように修正してflutter_localizationsパッケージをインストールする。

...
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
...

その後、次のようにMaterialApplocalizationsDelegatesオプションを追加します。

import 'package:flutter_localizations/flutter_localizations.dart';
...
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      localizationsDelegates: const [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      ...,
    );
  }
}
...

その後、showDatePicker関数のlocaleオプションに表示したい言語を設定します。ここでは日本語(Japanese)を設定しました。

...
final selectedDate = await showDatePicker(
  context: context,
  initialDate: date,
  firstDate: DateTime(2000),
  lastDate: DateTime.now(),
  initialEntryMode: DatePickerEntryMode.calendarOnly,
  locale: const Locale('ja', 'JP'),
);
...

このようにコードを修正して保存すると、次のようにカレンダーに表示される言語が英語ではなく日本語がうまく表示されることが確認できます。

Flutter showDatePicker - change locale of date picker

テストコード

次のようにテストコードを作成して、showDatePickerがうまく動作するか確認することができます。

...
testWidgets('Change date by DatePicker', (WidgetTester tester) async {
  DateTime date = DateTime.now();

  await tester.pumpWidget(const MyApp());

  final year = date.year.toString();
  final month = date.month.toString().padLeft(2, '0');
  final day = date.day.toString().padLeft(2, '0');

  expect(find.text('$year-$month-$day'), findsOneWidget);

  // Press cancel test
  await tester.tap(find.text('$year-$month-$day'));
  await tester.pump();
  await tester.tap(find.text('キャンセル')); // Cancel
  await tester.pump();
  expect(find.text('$year-$month-$day'), findsOneWidget);
  expect(find.text('キャンセル'), findsNothing);

  // Change date
  await tester.tap(find.text('$year-$month-$day'));
  await tester.pump();
  await tester.tap(find.text('15'));
  await tester.tap(find.text('OK'));
  await tester.pump();
  expect(find.text("$year-$month-15"), findsOneWidget);

  await tester.tap(find.text('$year-$month-15'));
  await tester.pump();
  await tester.tap(find.text('1'));
  await tester.tap(find.text('OK'));
  await tester.pump();
  expect(find.text("$year-$month-01"), findsOneWidget);
});
...

このテストコードではボタンを押してDatePickerを表示した後、日本語で表示されたキャンセル(キャンセル)ボタンを押して日付の変更をしなくてDatePickerを閉じるテストと実際日付を押して日付を変更するテストを作成してみました。

完了

これでshowDatePickerを使ってFlutterでカレンダーを表示して日付を変更する機能を実装する方法について調べてみました。日付を変更する必要がある場合、日付を直接入力させるより、DatePickerを表示してユーザがもっと楽に日付を変更することができるようにしてみてください。

私のブログが役に立ちましたか?下にコメントを残してください。それは私にとって大きな大きな力になります!

アプリ広報

今見てるブログを作成たDekuが開発したアプリを使ってみてください。
Dekuが開発したアプリはFlutterで開発されています。

興味がある方はアプリをダウンロードしてアプリを使ってくれると本当に助かります。

Posts