👻

Flutterでシンプルなストップウォッチを作った

2021/08/15に公開

動作の様子

参考にした記事

https://zenn.dev/kyo9bo/articles/066afd9cbcd4bd
こちらの記事を参考にし、ミリ秒単位までの表示、状態によって押せるボタンを変えるなどの機能を追加しました。

コード

状態管理には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