close

Flutter Countdown Timer

Image for post

In this article, I will assemble a check down clock with the assistance of the movement and utilizing custom paint.

Most importantly, make an application which restores the MaterialApp.

Image for post

Presently make another Widget CountDownTimer and ensure that it should be a Stateful Widget since we are utilizing liveliness and we should add TickerProviderStateMixen .

class CountDownTimer extends StatefulWidget {
  @override
  _CountDownTimerState createState() => _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {
}

Create an Animation Controller

Make a liveliness regulator and initialise it in initState() .

AnimationController controller;

@override
void initState() {
  super.initState();
  controller = AnimationController(
    vsync: this,
    duration: Duration(seconds: 5),
  );
}

Make a liveliness regulator and initialise it in initState() .

Create a Circular progress bar using Custom paint

Image for post

Create a class which extends CustomPainter

class CustomTimerPainter extends CustomPainter

Add properties

Now we will require a few properties so we can alter my custom painter class from my gadgets screen.

class CustomTimerPainter extends CustomPainter {
  CustomTimerPainter({
    this.animation,
    this.backgroundColor,
    this.color,
  }) : super(repaint: animation);

  final Animation<double> animation;
  final Color backgroundColor, color;
}

I am utilizing foundation tone and shading property for my Circular advancement bar and to enliven my advancement bar, I will require an activity.

Override methods

We will supersede our paint strategy which will use to paint our round advancement bar.

To start with, we will paint a circle and we will make a circular segment will move around the circle.

In the paint strategy, make a Paint item and add properties.

Paint paint = Paint()
  ..color = backgroundColor
  ..strokeWidth = 10.0
  ..strokeCap = StrokeCap.butt
  ..style = PaintingStyle.stroke;

Now draw a circle

canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);

When the circle is painted then will need to draw an arc to move.

paint.color = color;
double progress = (1.0 - animation.value) * 2 * math.pi;
canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);

Change the shade of the paint and update the cycle utilizing the current activity worth and draw the bend.

Presently we additionally have a supersede technique shouldRepaint .

@override
bool shouldRepaint(CustomTimerPainter old) {
  return animation.value != old.animation.value ||
      color != old.color ||
      backgroundColor != old.backgroundColor;
}

Here is the code for the CustomTimerPainter class

class CustomTimerPainter extends CustomPainter {
  CustomTimerPainter({
    this.animation,
    this.backgroundColor,
    this.color,
  }) : super(repaint: animation);

  final Animation<double> animation;
  final Color backgroundColor, color;

  @override
  void paint(Canvas canvas, Size size) {
    Paint paint = Paint()
      ..color = backgroundColor
      ..strokeWidth = 10.0
      ..strokeCap = StrokeCap.butt
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
    paint.color = color;
    double progress = (1.0 - animation.value) * 2 * math.pi;
    canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
  }

  @override
  bool shouldRepaint(CustomTimerPainter old) {
    return animation.value != old.animation.value ||
        color != old.color ||
        backgroundColor != old.backgroundColor;
  }
}

Create the UI

To vivify my Custom Progress bar we will wrap my an AnimatedBuilder and give the activity and it restores a CustomPaint Widget. At the point when My liveliness will begin the estimation of the circular segment will refresh in the custom painter class and update the UI

AnimatedBuilder(
  animation: controller,
  builder:
      (BuildContext context, Widget child) {
    return CustomPaint(
        painter: CustomTimerPainter(
      animation: controller,
      backgroundColor: Colors.white,
      color: themeData.indicatorColor,
    ));
  },
),

Furthermore, to begin and delay the movement Ill utilize the Floating Action Button, we have likewise Wrapped my FAB with AnimatedBuilder so we can refresh my play and respite status.

AnimatedBuilder(
    animation: controller,
    builder: (context, child) {
      return FloatingActionButton.extended(
          onPressed: () {
            if (controller.isAnimating)
              controller.stop();
            else {
              controller.reverse(
                  from: controller.value == 0.0
                      ? 1.0
                      : controller.value);
            }
          },
          icon: Icon(controller.isAnimating
              ? Icons.pause
              : Icons.play_arrow),
          label: Text(
              controller.isAnimating ? "Pause" : "Play"));
    }),

Now if we see the app, it will look like this

Image for post

Now Wrap the CustomTimerPainter inside the Stack and add text to represent the value.

   return Scaffold(
      backgroundColor: Colors.white10,
      body: AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return Padding(
              padding: EdgeInsets.all(8.0),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Expanded(
                    child: Align(
                      alignment: FractionalOffset.center,
                      child: AspectRatio(
                        aspectRatio: 1.0,
                        child: Stack(
                          children: <Widget>[
                            Positioned.fill(
                              child:
                              AnimatedBuilder(
                                animation: controller,
                                builder:
                                    (BuildContext context, Widget child) {
                                  return CustomPaint(
                                      painter: CustomTimerPainter(
                                    animation: controller,
                                    backgroundColor: Colors.white,
                                    color: themeData.indicatorColor,
                                  ));
                                },
                              ),
                            ),
                            Align(
                              alignment: FractionalOffset.center,
                              child: Column(
                                mainAxisAlignment:
                                    MainAxisAlignment.spaceEvenly,
                                crossAxisAlignment:
                                    CrossAxisAlignment.center,
                                children: <Widget>[
                                  Text(
                                    "Count Down Timer",
                                    style: TextStyle(
                                        fontSize: 20.0,
                                        color: Colors.white),
                                  ),
                                  AnimatedBuilder(
                                      animation: controller,
                                      builder: (BuildContext context,
                                          Widget child) {
                                        return Text(
                                          timerString,
                                          style: TextStyle(
                                              fontSize: 112.0,
                                              color: Colors.white),
                                        );
                                      }),
                                ],
                              ),
                            ),
                          ],
                        ),
                      ),
                    ),
                  ),
                  AnimatedBuilder(
                      animation: controller,
                      builder: (context, child) {
                        return FloatingActionButton.extended(
                            onPressed: () {
                              if (controller.isAnimating)
                                controller.stop();
                              else {
                                controller.reverse(
                                    from: controller.value == 0.0
                                        ? 1.0
                                        : controller.value);
                              }
                            },
                            icon: Icon(controller.isAnimating
                                ? Icons.pause
                                : Icons.play_arrow),
                            label: Text(
                                controller.isAnimating ? "Pause" : "Play"));
                      }),
                ],
              ),
            );
          }),
    );

To convert the animation duration into time String.

String get timerString {
  Duration duration = controller.duration * controller.value;
  return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
}
Image for post

Here is the code of CountDownTimer Widget

class CountDownTimer extends StatefulWidget {
  @override
  _CountDownTimerState createState() => _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {
  AnimationController controller;

  String get timerString {
    Duration duration = controller.duration * controller.value;
    return '${duration.inMinutes}:${(duration.inSeconds % 60).toString().padLeft(2, '0')}';
  }

  @override
  void initState() {
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(seconds: 5),
    );
  }

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Scaffold(
      backgroundColor: Colors.white10,
      body:
      AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            return Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    color: Colors.amber,
                    height:
                        controller.value * MediaQuery.of(context).size.height,
                  ),
                ),
                Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Expanded(
                        child: Align(
                          alignment: FractionalOffset.center,
                          child: AspectRatio(
                            aspectRatio: 1.0,
                            child: Stack(
                              children: <Widget>[
                                Positioned.fill(
                                  child: CustomPaint(
                                      painter: CustomTimerPainter(
                                        animation: controller,
                                        backgroundColor: Colors.white,
                                        color: themeData.indicatorColor,
                                      )),
                                ),
                                Align(
                                  alignment: FractionalOffset.center,
                                  child: Column(
                                    mainAxisAlignment:
                                        MainAxisAlignment.spaceEvenly,
                                    crossAxisAlignment:
                                        CrossAxisAlignment.center,
                                    children: <Widget>[
                                      Text(
                                        "Count Down Timer",
                                        style: TextStyle(
                                            fontSize: 20.0,
                                            color: Colors.white),
                                      ),
                                      Text(
                                        timerString,
                                        style: TextStyle(
                                            fontSize: 112.0,
                                            color: Colors.white),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                      AnimatedBuilder(
                          animation: controller,
                          builder: (context, child) {
                            return FloatingActionButton.extended(
                                onPressed: () {
                                  if (controller.isAnimating)
                                    controller.stop();
                                  else {
                                    controller.reverse(
                                        from: controller.value == 0.0
                                            ? 1.0
                                            : controller.value);
                                  }
                                },
                                icon: Icon(controller.isAnimating
                                    ? Icons.pause
                                    : Icons.play_arrow),
                                label: Text(
                                    controller.isAnimating ? "Pause" : "Play"));
                          }),
                    ],
                  ),
                ),
              ],
            );
          }),
    );
  }
}

I have wrapped the root body gadget and added another Container and enlivening with activity esteem.

Container(
  color: Colors.amber,
  height:
      controller.value * MediaQuery.of(context).size.height,
),
Image for post

Summery

It’s all About this issue. Hope all solution helped you a lot. Comment below Your thoughts and your queries. Also, Comment below which solution worked for you? Thank You.

Also Read

Leave a Comment