Search code examples
datetimedartfluttercountdown

flutter - how to best practice make a countdown widget


Im developing a soccer match schedule application see image. I want to add a countdown when kick off the match. How to best practice make a countdown widget with the format hh : mm : ss ?


Solution

  • Both in the comment will have good results. It is also best to rely on Flutter documentation for guidance.

    With that, I've made a little sample of a countdown timer based on your requirements.

    First, I've tried to define what kind of input I'm going to use. Decided to implement the input this way:

    //Update the time in 'YYYY-MM-DD HH:MM:SS' format
    final eventTime = DateTime.parse('2021-01-09 03:41:00');
    

    So that I can supply the exact date and time I needed.

    Then get the difference from the current date and time and convert it to seconds:

    int timeDiff = eventTime.difference(DateTime.now()).inSeconds;
    

    Then created a function that would handle the clocking of the timer:

    void handleTick() {
        if (timeDiff > 0) {
          if (isActive) {
            setState(() {
              if (eventTime != DateTime.now()) {
                timeDiff = timeDiff - 1;
              } else {
                print('Times up!');
                //Do something
              }
            });
          }
        }
      }
    

    So when the timer is working as expected, I've just used mathematical operation to define the remaining days, hours, minutes and seconds:

    int days = timeDiff ~/ (24 * 60 * 60) % 24;
    int hours = timeDiff ~/ (60 * 60) % 24;
    int minutes = (timeDiff ~/ 60) % 60;
    int seconds = timeDiff % 60;
    

    If you just need the HH:MM:SS format you can just play around and omit that section, check the working code:

    import 'package:flutter/material.dart';
    import 'dart:async';
    
    void main() => runApp(TimerApp());
    
    class TimerApp extends StatefulWidget {
      @override
      _TimerAppState createState() => _TimerAppState();
    }
    
    //Update the time in 'YYYY-MM-DD HH:MM:SS' format
    final eventTime = DateTime.parse('2021-01-09 03:41:00');
    
    class _TimerAppState extends State<TimerApp> {
      static const duration = const Duration(seconds: 1);
    
      int timeDiff = eventTime.difference(DateTime.now()).inSeconds;
      bool isActive = false;
    
      Timer timer;
    
      void handleTick() {
        if (timeDiff > 0) {
          if (isActive) {
            setState(() {
              if (eventTime != DateTime.now()) {
                timeDiff = timeDiff - 1;
              } else {
                print('Times up!');
                //Do something
              }
            });
          }
        }
      }
    
      @override
      Widget build(BuildContext context) {
        if (timer == null) {
          timer = Timer.periodic(duration, (Timer t) {
            handleTick();
          });
        }
    
        int days = timeDiff ~/ (24 * 60 * 60) % 24;
        int hours = timeDiff ~/ (60 * 60) % 24;
        int minutes = (timeDiff ~/ 60) % 60;
        int seconds = timeDiff % 60;
    
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            backgroundColor: Colors.white,
            appBar: AppBar(
              backgroundColor: Colors.grey[700],
              title: Center(
                child: Text('Countdown Timer'),
              ),
            ),
            body: Center(
              child: Column(
                mainAxisSize: MainAxisSize.min,
                children: <Widget>[
                  Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: <Widget>[
                      LabelText(
                          label: 'DAYS', value: days.toString().padLeft(2, '0')),
                      LabelText(
                          label: 'HRS', value: hours.toString().padLeft(2, '0')),
                      LabelText(
                          label: 'MIN', value: minutes.toString().padLeft(2, '0')),
                      LabelText(
                          label: 'SEC', value: seconds.toString().padLeft(2, '0')),
                    ],
                  ),
                  SizedBox(height: 60),
                  Container(
                    width: 200,
                    height: 47,
                    margin: EdgeInsets.only(top: 30),
                    child: RaisedButton(
                      color: isActive ? Colors.grey : Colors.green,
                      shape: RoundedRectangleBorder(
                          borderRadius: BorderRadius.circular(25)),
                      child: Text(isActive ? 'STOP' : 'START'),
                      onPressed: () {
                        setState(() {
                          isActive = !isActive;
                        });
                      },
                    ),
                  )
                ],
              ),
            ),
          ),
        );
      }
    }
    
    class LabelText extends StatelessWidget {
      LabelText({this.label, this.value});
    
      final String label;
      final String value;
    
      @override
      Widget build(BuildContext context) {
        return Container(
          margin: EdgeInsets.symmetric(horizontal: 5),
          padding: EdgeInsets.all(20),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(25),
            color: Colors.grey,
          ),
          child: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              Text(
                '$value',
                style: TextStyle(
                    color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
              ),
              Text(
                '$label',
                style: TextStyle(
                  color: Colors.white70,
                ),
              ),
            ],
          ),
        );
      }
    }
    

    Here is the output of the countdown timer I've created:

    enter image description here