Повтор анимации и корректировки в флаттере - PullRequest
0 голосов
/ 14 марта 2019

Я пытаюсь клонировать таймер приложения, которое я использую во время тренировки: Сильный.До сих пор мне удалось реализовать все основные функции и анимации (которых немного).Я знаю, что мой код грязный, и, возможно, есть лучшие способы реализовать то, что я пытаюсь сделать, если есть какие-то предложения, которые они также ценят.У меня две проблемы с моим заявлением.1. Когда таймер запускается, я получаю следующую ошибку:

flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY 

╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building Peinture(dirty, state: _PeintureState#82e34):
flutter: The getter 'inMilliseconds' was called on null.
flutter: Receiver: null
flutter: Tried calling: inMilliseconds
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
flutter: #1      _PeintureState.build (package:workout_timer/main.dart:241:72)
flutter: #2      StatefulElement.build (package:flutter/src/widgets/framework.dart:3809:27)
flutter: #3      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3721:15)
flutter: #4      Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #5      StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #6      Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #7      SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
flutter: #8      Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #9      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #10     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #11     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #12     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #13     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #14     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #15     StatelessElement.update (package:flutter/src/widgets/framework.dart:3781:5)
flutter: #16     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #17     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4585:32)
flutter: #18     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4975:17)
flutter: #19     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #20     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #21     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #22     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #23     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #24     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #25     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #26     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #27     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #28     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4585:32)
flutter: #29     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4975:17)
flutter: #30     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #31     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #32     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #33     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #34     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #35     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #36     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #37     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #38     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #39     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #40     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #41     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #42     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #43     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
flutter: #44     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #45     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #46     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #47     StatelessElement.update (package:flutter/src/widgets/framework.dart:3781:5)
flutter: #48     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #49     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4867:14)
flutter: #50     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #51     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #52     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #53     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #54     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #55     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #56     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #57     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #58     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #59     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #60     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #61     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #62     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #63     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #64     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #65     ProxyElement.update (package:flutter/src/widgets/framework.dart:3990:5)
flutter: #66     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #67     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #68     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #69     StatefulElement.update (package:flutter/src/widgets/framework.dart:3878:5)
flutter: #70     Element.updateChild (package:flutter/src/widgets/framework.dart:2742:15)
flutter: #71     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3732:16)
flutter: #72     Element.rebuild (package:flutter/src/widgets/framework.dart:3547:5)
flutter: #73     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2286:33)
flutter: #74     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:676:20)
flutter: #75     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:219:5)
flutter: #76     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:990:15)
flutter: #77     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:930:9)
flutter: #78     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:842:5)
flutter: #79     _invoke (dart:ui/hooks.dart:154:13)
flutter: #80     _drawFrame (dart:ui/hooks.dart:143:3)
flutter: ════════════════════════════════════════════════════════════════════════════════════════════════════

, которую я обязательно проверил, я не получаю ничего нулевого, но все равно получаю это.

Ивторой.Когда таймер заканчивается, я получаю следующую ошибку:

[VERBOSE-2:shell.cc(184)] Dart Error: Unhandled exception:
setState() called after dispose(): _TimeState#10749(lifecycle state: defunct, not mounted)
This error happens if you call setState() on a State object for a widget that no longer appears in the widget tree (e.g., whose parent widget no longer includes the widget in its build). This error can occur when code calls setState() from a timer or an animation callback. The preferred solution is to cancel the timer or stop listening to the animation in the dispose() callback. Another solution is to check the "mounted" property of this object before calling setState() to ensure the object is still in the tree.
This error might indicate a memory leak if setState() is being called because another object is retaining a reference to this State object after it has been removed from the tree. To avoid memory leaks, consider breaking the reference to this object during dispose().
#0      State.setState.<anonymous closure> (package:flutter/src/widgets/framewo<…>

И когда я пытаюсь запустить таймер снова, я получаю это:

flutter: Another exception was thrown: NoSuchMethodError: The getter 'inMilliseconds' was called on null.

Вот мой код:

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:fluttery/layout.dart';

Duration time;
Duration previousTime;
Duration currentTime;
AnimationController timeController, circleController;
bool reverse = false;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {

  Stopwatch stopwatch = new Stopwatch();

  @override
  void initState() {
    super.initState();
    timeController = new AnimationController(
      duration: const Duration(milliseconds: 250),
      vsync: this,
    );
    timeController.addListener(() {
      setState(() {});
    });
  }

  @override
  void dispose() {
    timeController.dispose();
    circleController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Center(
            child: Opacity(
              opacity: timeController.value != null ? 1.0 - timeController.value : 1.0,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 1);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("1:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 2);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("2:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 3);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("3:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 5);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("5:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                ],
              ),
            ),
          ),
          Center(
            child: Opacity(
              opacity: timeController.value != null ? 0.0 + timeController.value : 0.0,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: time != null ? buildTimes(stopwatch, time, previousTime) : []
              ),
            ),
          ),
          CenterAbout(
              position: Offset(MediaQuery.of(context).size.width / 2,
                  MediaQuery.of(context).size.height / 2),
              child: Peinture(color: Color.fromRGBO(224, 245, 255, 1.0), animate: false)
          ),
          CenterAbout(
            position: Offset(MediaQuery.of(context).size.width / 2,
                MediaQuery.of(context).size.height / 2),
            child: Peinture(color: Colors.blue, animate: true)
          )
        ],
      ),
    );
  }
}

List<Widget> buildTimes(stopwatch, time, previousTime) {
  return [
    Time(stopwatch: stopwatch, time: time),
    Text(
      previousTime != null
          ? previousTime.toString().substring(3, 7)
          : "",
      style: TextStyle(
          fontWeight: FontWeight.bold,
          fontSize: 30.0,
          color: Colors.black54),
    ),
  ];
}

class Peinture extends StatefulWidget {

  final Color color;
  final bool animate;

  Peinture({this.color, this.animate});

  @override
  _PeintureState createState() => _PeintureState(color: color, animate: animate);
}

class _PeintureState extends State<Peinture> {
  Timer timer;
  Color color;
  bool animate;

  _PeintureState({this.color, this.animate}) {
    timer = Timer.periodic(Duration(milliseconds: 1), callback);
  }

  void callback(Timer timer) {
    setState(() {
      if (currentTime != null) {
        print(currentTime.inMilliseconds);
        if (currentTime.inMilliseconds <= 0) {
          reverse = true;
          timeController.reverse();
          previousTime = null;
          time = previousTime;
          currentTime = time;
          reverse = false;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: reverse == false ? 1.0 : timeController.value,
      child: CustomPaint(
        painter: CirclePainter(
          radius: 150.0,
          thickness: 8.0,
          color: color,
          startAngle: -pi / 2,
          endAngle: time != null && animate ? -pi / 2 + (((currentTime.inMilliseconds - circleController.value)) /  60000) * (2*pi) : -pi / 2 + (2 * pi) - (0 / (2*pi)),
        ),
      ),
    );
  }
}


class CirclePainter extends CustomPainter {
  final double radius;
  final double thickness;
  final Color color;
  final double startAngle;
  final double endAngle;
  final Paint circlePaint;

  CirclePainter({this.radius, this.thickness, this.color, this.startAngle, this.endAngle})
      : circlePaint = new Paint()
          ..color = color
          ..strokeWidth = thickness
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawArc(Rect.fromLTWH(-radius, -radius, radius * 2, radius * 2),
        startAngle, endAngle - startAngle, false, circlePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class Time extends StatefulWidget {
  final Duration time;
  final Stopwatch stopwatch;

  Time({this.stopwatch, this.time});

  @override
  _TimeState createState() => _TimeState(stopwatch: stopwatch, time: time);
}

class _TimeState extends State<Time> {
  Timer timer;
  Duration time;
  Stopwatch stopwatch;

  _TimeState({this.time, this.stopwatch}) {
    timer = new Timer.periodic(new Duration(milliseconds: 1), callback);
  }

  void callback(Timer timer) {
    if (stopwatch.isRunning) {
      setState(() {
        currentTime = time - stopwatch.elapsed;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Text(
      currentTime != null ? currentTime.toString().substring(3, 7) : "",
      style: TextStyle(
          fontWeight: FontWeight.bold, fontSize: 60.0, color: Colors.black87),
    );
  }
}

Спасибо за помощь, и мы будем благодарны за любые предложения относительно того, как вы поступите.

1 Ответ

0 голосов
/ 14 марта 2019

Попробуйте это

import 'dart:async';
import 'dart:math';

import 'package:flutter/material.dart';
import 'package:fluttery/layout.dart';

Duration time;
Duration previousTime;
Duration currentTime;
AnimationController timeController, circleController;
bool reverse = false;

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> with TickerProviderStateMixin {
  Stopwatch stopwatch = new Stopwatch();

  @override
  void initState() {
    super.initState();
    timeController = new AnimationController(
      duration: const Duration(milliseconds: 250),
      vsync: this,
    );
    timeController.addListener(() {
      setState(() {});
    });
  }

  @override
  void dispose() {
    timeController.dispose();
    circleController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Stack(
        children: <Widget>[
          Center(
            child: Opacity(
              opacity: timeController.value != null
                  ? 1.0 - timeController.value
                  : 1.0,
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 1);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("1:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 2);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("2:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 3);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("3:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                  new FlatButton(
                    onPressed: () {
                      setState(() {
                        previousTime = Duration(minutes: 5);
                        time = previousTime;
                        timeController.forward();
                        stopwatch.start();
                        circleController = new AnimationController(
                          duration: Duration(milliseconds: time.inMilliseconds),
                          vsync: this,
                        );
                        circleController.addListener(() {
                          setState(() {});
                        });
                        circleController.forward();
                      });
                    },
                    child: Text("5:00",
                        style: TextStyle(
                            fontWeight: FontWeight.bold, fontSize: 16.0)),
                  ),
                ],
              ),
            ),
          ),
          Center(
            child: Opacity(
              opacity: timeController.value != null
                  ? 0.0 + timeController.value
                  : 0.0,
              child: Column(
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: time != null
                      ? buildTimes(stopwatch, time, previousTime)
                      : []),
            ),
          ),
          CenterAbout(
            position: Offset(MediaQuery.of(context).size.width / 2,
                MediaQuery.of(context).size.height / 2),
            child: Peinture(
                color: Color.fromRGBO(224, 245, 255, 1.0), animate: false),
          ),
          CenterAbout(
            position: Offset(MediaQuery.of(context).size.width / 2,
                MediaQuery.of(context).size.height / 2),
            child: Peinture(color: Colors.blue, animate: true),
          )
        ],
      ),
    );
  }
}

List<Widget> buildTimes(stopwatch, time, previousTime) {
  return [
    Time(stopwatch: stopwatch, time: time),
    Text(
      previousTime != null ? previousTime.toString().substring(3, 7) : "",
      style: TextStyle(
          fontWeight: FontWeight.bold, fontSize: 30.0, color: Colors.black54),
    ),
  ];
}

class Peinture extends StatefulWidget {
  final Color color;
  final bool animate;

  Peinture({this.color, this.animate});

  @override
  _PeintureState createState() =>
      _PeintureState(color: color, animate: animate);
}

class _PeintureState extends State<Peinture> {
  Timer timer;
  Color color;
  bool animate;

  _PeintureState({this.color, this.animate}) {
    timer = Timer.periodic(Duration(milliseconds: 1), callback);
  }

  void callback(Timer timer) {
    setState(() {
      if (currentTime != null) {
        if (currentTime.inMilliseconds <= 0) {
          reverse = true;
          timeController.reverse();
          previousTime = null;
          time = previousTime;
          currentTime = time;
          reverse = false;
        }
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    return Opacity(
      opacity: reverse == false ? 1.0 : timeController.value,
      child: CustomPaint(
        painter: CirclePainter(
          radius: 150.0,
          thickness: 8.0,
          color: color,
          startAngle: -pi / 2,
          endAngle: time != null && animate && currentTime != null
              ? -pi / 2 +
                  (((currentTime.inMilliseconds - circleController.value)) /
                          60000) *
                      (2 * pi)
              : -pi / 2 + (2 * pi) - (0 / (2 * pi)),
        ),
      ),
    );
  }
}

class CirclePainter extends CustomPainter {
  final double radius;
  final double thickness;
  final Color color;
  final double startAngle;
  final double endAngle;
  final Paint circlePaint;

  CirclePainter(
      {this.radius, this.thickness, this.color, this.startAngle, this.endAngle})
      : circlePaint = new Paint()
          ..color = color
          ..strokeWidth = thickness
          ..style = PaintingStyle.stroke
          ..strokeCap = StrokeCap.round;

  @override
  void paint(Canvas canvas, Size size) {
    canvas.drawArc(Rect.fromLTWH(-radius, -radius, radius * 2, radius * 2),
        startAngle, endAngle - startAngle, false, circlePaint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class Time extends StatefulWidget {
  final Duration time;
  final Stopwatch stopwatch;

  Time({this.stopwatch, this.time});

  @override
  _TimeState createState() => _TimeState(stopwatch: stopwatch, time: time);
}

class _TimeState extends State<Time> {
  Timer timer;
  Duration time;
  Stopwatch stopwatch;

  _TimeState({this.time, this.stopwatch}) {
    timer = new Timer.periodic(new Duration(milliseconds: 1), callback);
  }

  void callback(Timer timer) {
    if (stopwatch.isRunning) {
      setState(() {
        currentTime = time - stopwatch.elapsed;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Text(
      currentTime != null ? currentTime.toString().substring(3, 7) : "",
      style: TextStyle(
          fontWeight: FontWeight.bold, fontSize: 60.0, color: Colors.black87),
    );
  }
}
...