今回はFlutterで簡単なストップウォッチを作成してみました。
環境
- OS : Windous10
- Flutter : v2.2.3
完成品
0秒からではなく、どの時間からでも開始できるストップウォッチにしてみました。
ストップウォッチを使っていて、途中から始めたい事がよくあったので、、、
機能は3つです。
1. 開始時間設定
2. ストップウォッチ開始、停止
3. リセット
Flutter習得
習得にはKBOYさんが運営しているFlutter大学の動画を見させていただきました。
環境構築から、簡単なYoutube風アプリ(側だけ)の作成まで、動画を見ながら2日で実施出来ました。
※2020年の動画で少し古いですが動作しました。
- 環境構築 : https://www.youtube.com/playlist?list=PLuLRJz1UnJzE4-HlkLTG8ARbZ2TDBNHzZ
- Flutter基礎 : https://www.youtube.com/playlist?list=PLuLRJz1UnJzEDjRr1XkqyOzFzUi3Df4B0
ストップウォッチ作成
1日でサクッと作成しました。
FlutterPicker というプラグインを使用すると、時間設定が楽に作成できます。
タイマー部分は、Timerで1秒の定期実行でカウントアップの関数を呼び出しています。
画面の更新は、SetStateではなくProviderパッケージを使い、notifyListeners()
で変更を通知しています。
Widgetのツリー
ソースコード
/* main.dart メイン画面 */ import 'package:flutter/material.dart'; import 'package:flutter_picker/Picker.dart'; import 'package:intl/intl.dart'; import 'package:provider/provider.dart'; import 'main_model.dart'; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { return MaterialApp( title: 'ストップウォッチ', home: ChangeNotifierProvider<MainModel>( create: (context) => MainModel(), child: Scaffold( appBar: AppBar( title: Text('ストップウォッチ'), ), body: Consumer<MainModel>( builder: (context, model, child) { return Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ TextButton( // タイマー時間表示 + Editボタン onPressed: () { if (!model.isEditTimeEnabled) return; // 時間設定ウインド表示 Picker( adapter: DateTimePickerAdapter( type: PickerDateTimeType.kHMS, value: model.timerTime, customColumnType: [3, 4, 5], ), title: Text("Select Time"), onConfirm: (Picker, List values) { model.changeTimerTime(DateTime.utc( 0, 0, 0, values[0], values[1], values[2])); }, ).showModal(context); }, child: Text(DateFormat.Hms().format(model.timerTime), style: TextStyle( fontSize: 80, )), ), Row( // START,STOP,RESETボタン mainAxisAlignment: MainAxisAlignment.center, children: [ Padding( // STARTボタン padding: const EdgeInsets.all(8.0), child: ElevatedButton.icon( onPressed: !model.isStartEnabled ? null : () { model.startTimer(); }, icon: Icon(Icons.play_arrow), label: Text('START')), ), Padding( // STOPボタン padding: const EdgeInsets.all(8.0), child: ElevatedButton.icon( onPressed: !model.isStopEnabled ? null : () { model.stopTimer(); }, icon: Icon(Icons.stop), label: Text('STOP')), ), Padding( // RESETボタン padding: const EdgeInsets.all(8.0), child: ElevatedButton.icon( onPressed: !model.isResetEnabled ? null : () { model.resetTimerTime(); }, icon: Icon(Icons.clear), label: Text('RESET')), ) ], ), ], ), ); }, ), ), ), ); } }
/* main_model.dart メイン画面のデータモデル */ import 'dart:async'; import 'package:flutter/material.dart'; class MainModel extends ChangeNotifier { Timer? timer; DateTime timerTime = DateTime(0); bool isStartEnabled = true; bool isStopEnabled = false; bool isResetEnabled = true; bool isEditTimeEnabled = true; // 開始時間変更 void changeTimerTime(DateTime time) { timerTime = time; notifyListeners(); } // 開始時間リセット void resetTimerTime() { timerTime = new DateTime(0); notifyListeners(); } // ストップウォッチ開始 void startTimer() { if (timer == null) { timer = Timer.periodic(Duration(seconds: 1), (timer) { countUpTime(1); }); } isStartEnabled = false; isStopEnabled = true; isResetEnabled = false; isEditTimeEnabled = false; notifyListeners(); } // ストップウォッチ停止 void stopTimer() { timer!.cancel(); timer = null; notifyListeners(); isStartEnabled = true; isStopEnabled = false; isResetEnabled = true; isEditTimeEnabled = true; notifyListeners(); } // 1s カウントアップ void countUpTime(int second) { timerTime = timerTime.add(Duration(seconds: second)); notifyListeners(); } }
参考
- Flutter大学 : Flutter大学 - YouTube
- FlutterPicker を使う : https://rinoguchi.net/2021/05/flutter-hour-minute-second-input.html