[Widget]TimePickerで時刻設定する

動作環境: Flutter 2.8.1 Dart 2.15.1
LINEでこのページを共有するTwitterでこのページを共有するこのページをはてなブックマークに追加

FlutterではTimePickerを呼び出すことで簡単に時刻設定機能を導入することが可能です。
早速試してみましょう。サンプルコードはこちらです。

lib/main.dart
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
TimeOfDay? _selectedTime;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Builder(builder: (context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_selectedTime == null
? const Text(
'時間を選択してください',
style: TextStyle(fontSize: 30.0),
)
: Text(
'${_selectedTime!.hour.toString()}:${_selectedTime!.minute.toString()}',
style: const TextStyle(fontSize: 40.0),
),
const SizedBox(
height: 40.0,
),
ElevatedButton(
onPressed: () {
_selectTime(context);
},
child: const Text(
'選択する',
style: TextStyle(fontSize: 30.0),
),
)
],
),
),
);
}));
}
Future _selectTime(BuildContext context) async {
final int selectedHour = _selectedTime?.hour ?? 9;
final int selectedMinute = _selectedTime?.minute ?? 30;
final initialTime = TimeOfDay(hour: selectedHour, minute: selectedMinute);
final time = await showTimePicker(
context: context,
initialTime: initialTime,
);
if (time != null) {
setState(() => _selectedTime = time);
} else {
return;
}
}
}

アプリを起動して、「選択する」ボタンを押すとTimePickerが出現します。
そこで任意の時刻を設定して「OK」を押すと、TimePickerが閉じてテキスト部分に選択した時刻が反映されるようにしています。
TimePickerのサンプル
今回、選択した時刻を状態として保持しておきたいため、StateFullWidgetの中にTimePickerに関連するコードを書いています。
以下のように15行目で状態保持用の変数を設定しています。

lib/main.dart
class _MyAppState extends State<MyApp> {
TimeOfDay? _selectedTime;
@override
Widget build(BuildContext context) {

TimeOfDayはFlutter標準、時刻用の型です。
この_selectedTimeにユーザーが選択した時刻情報を保持するようにします。

ボタンを押した時のコードを見ていきましょう。
以下のコードを見てください。

lib/main.dart
ElevatedButton(
onPressed: () {
_selectTime(context);
},
child: const Text(
'選択する',
style: TextStyle(fontSize: 30.0),
),
)

onPressed:にボタンを押した時の処理を書いています。
今回は_selectTimeひとつだけです。このメソッドはlib/main.dartの下部で定義しています。
以下のコードを見てください。

lib/main.dart
Future _selectTime(BuildContext context) async {
final int selectedHour = _selectedTime?.hour ?? 9;
final int selectedMinute = _selectedTime?.minute ?? 30;
final initialTime = TimeOfDay(hour: selectedHour, minute: selectedMinute);
final time = await showTimePicker(
context: context,
initialTime: initialTime,
);
if (time != null) {
setState(() => _selectedTime = time);
} else {
return;
}
}

この59行目から始まるメソッドが今回の心臓部ですね。
64行目でshowTimePickerを実行しています。ここを通るとTimePickerが画面に出現します。

今回引数にはinitialTimeを設定しています。ここには最初にTimePicker上で選択している時刻を指定します。
60行目、61行目でやっているようにもし_selectedTimeにすでに時刻が設定されている(= 以前に選択している)場合はそちらを初期表示に使用しています。もし_selectedTimeに何も設定されていないときはデフォルト値として09:30の値が設定されるようにしています。

そしてTimePickerが閉じられると69行目以降の処理が走り出します。

ここで「OK」ボタンをユーザーが押したときはtimeの変数に新しく選択した時刻情報が格納されています。
これを70行目のように_selectedTimeに設定しています。

一方でキャンセルボタンを押したなどで何も変更がなかったときは何もせずにreturnで終了していることがわかります。

こうして得られた時刻は文字列として画面に表示されます。
少し上に戻ります。以下のコードを見てください。

lib/main.dart
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_selectedTime == null
? const Text(
'時間を選択してください',
style: TextStyle(fontSize: 30.0),
)
: Text(
'${_selectedTime!.hour.toString()}:${_selectedTime!.minute.toString()}',
style: const TextStyle(fontSize: 40.0),
),

31行目で_selectedTimeの値の有無を基準にして表示内容を切り分けしています。
TimePickerで時刻が設定された後は、36行目以降が有効になります。

ここでは_selectedTimeの情報を文字列として展開しています。

DropdownButtonなどを使って自力で時刻設定用のUIを作ることもできますが結構手間がかかります。
思わぬ不具合も発生することも考慮すると、既にある部品を採用することを考えてみてもいいかもしれません。