在Flutter中重复动画和调整

时间:2019-03-14 01:21:43

标签: animation dart flutter mobile-development flutter-animation

我正在尝试克隆锻炼时使用的应用程序的计时器:强大。到目前为止,我已经实现了所有主要功能和动画(并不很多)。我知道我的代码很乱,如果有任何建议,也可能有更好的方法来实现我要尝试执行的操作。我的应用程序遇到两个问题。 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 :(得分:0)

尝试一下

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),
    );
  }
}