👻
Flutterでシンプルなストップウォッチを作った
動作の様子
参考にした記事
こちらの記事を参考にし、ミリ秒単位までの表示、状態によって押せるボタンを変えるなどの機能を追加しました。
コード
状態管理にはproviderパッケージを使用しました。
ディレクトリ構成はこんな感じです。
lib
├── models
│ └ stop_watch_model.dart
├── view
│ └ main_page.dart
└main.dart
main.dart
main.dart
import 'package:simple_stop_watch/view/main_page.dart';
import 'package:flutter/material.dart';
void main() => runApp(MainPage());
後述するMainPageクラスを呼び出すだけです。
main_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:simple_stop_watch/models/stop_watch_model.dart';
class MainPage extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(title: 'provider demo', home: _ProviderWidget());
}
}
class _ProviderWidget extends StatelessWidget {
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider<StopWatchModel>(
create: (context) => StopWatchModel(),
)
],
child: _MainPageBody(),
);
}
}
class _MainPageBody extends StatelessWidget {
Widget build(BuildContext context) {
final stopWatchModel = Provider.of<StopWatchModel>(context);
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: Text('シンプルストップウォッチ'),
),
// 再描画したい箇所だけConsumerで囲む
body: Center(
child: Column(
children: [
Consumer<StopWatchModel>(
builder: (context, model, _) => Text(
model.stopWatchTimeDisplay,
style: Theme.of(context).textTheme.headline2,
)),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: stopWatchModel.isStartPressed
? stopWatchModel.startStopWatch
: null,
child: Text('スタート')),
SizedBox(
width: 10,
),
ElevatedButton(
onPressed: stopWatchModel.isStopPressed
? null
: stopWatchModel.stopStopWatch,
child: Text('ストップ')),
SizedBox(
width: 10,
),
ElevatedButton(
onPressed: stopWatchModel.isResetPressed
? null
: stopWatchModel.resetStopWatch,
child: Text('リセット')),
],
),
],
),
));
}
}
stop_watch_model.dart
stop_watch_model.dart
import 'package:flutter/material.dart';
import 'dart:async';
class StopWatchModel extends ChangeNotifier {
bool isStopPressed = true;
bool isResetPressed = true;
bool isStartPressed = true;
String stopWatchTimeDisplay = '00:00:00:00';
// Stopwatch型を指定
Stopwatch swatch = Stopwatch();
final dul = const Duration(milliseconds: 10);
void startTimer() {
Timer(dul, keepRunning);
}
void keepRunning() {
if (swatch.isRunning) {
startTimer();
}
int milliSeconds = ((swatch.elapsedMilliseconds / 10).floor() % 100);
this.stopWatchTimeDisplay =
(swatch.elapsed.inHours).toString().padLeft(2, '0') +
':' +
(swatch.elapsed.inMinutes % 60).toString().padLeft(2, '0') +
':' +
(swatch.elapsed.inSeconds % 60).toString().padLeft(2, '0') +
':' +
(milliSeconds).toString().padLeft(2, '0');
notifyListeners();
}
startStopWatch() {
this.isStopPressed = false;
this.isStartPressed = false;
this.isResetPressed = false;
swatch.start();
startTimer();
notifyListeners();
}
stopStopWatch() {
this.isStopPressed = true;
this.isResetPressed = false;
this.isStartPressed = true;
swatch.stop();
notifyListeners();
}
resetStopWatch() {
this.isResetPressed = true;
this.isStartPressed = true;
this.isStopPressed = true;
swatch.stop();
swatch.reset();
stopWatchTimeDisplay = '00:00:00:00';
notifyListeners();
}
}
Discussion