skip to Main Content

I want to use a time countdown timer for date based on day, hour, minute and second. I found a code that does this for me.
This is the code:

import 'dart:async';
import 'package:flutter/material.dart';

class Time extends StatefulWidget {
  const Time({Key? key}) : super(key: key);

  @override
  State<Time> createState() => _TimeState();
}

final eventTime = DateTime.parse('2024-01-10 03:41:00');
class _TimeState extends State<Time> {

  static const duration = Duration(seconds: 1);
  int timeDiff = eventTime.difference(DateTime.now()).inSeconds;
  late Timer timer;
  bool isActive = true;

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

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

  @override
  void initState() {
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    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 Scaffold(
        appBar: AppBar(
          backgroundColor: const Color(0x00fafafa),
          elevation: 0,
          leading: const BackButton(color: Colors.deepOrange,),
        ),
        body: SingleChildScrollView(
          child: Column(
            children: [
              Column(
                children: [
                  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')),
                    ],
                  ),
                ],
              ),
            ],
          ),
        )
    );
  }
}


class LabelText extends StatelessWidget {
  const LabelText({super.key, required this.label, required this.value});

  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    return Container(
      margin: const EdgeInsets.symmetric(horizontal: 5),
      padding: const EdgeInsets.all(20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(25),
        color: Colors.grey,
      ),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        children: <Widget>[
          Text(
            value,
            style: const TextStyle(
                color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold),
          ),
          Text(
            label,
            style: const TextStyle(
              color: Colors.white70,
            ),
          ),
        ],
      ),
    );
  }
}

But these codes cannot show the number of remaining days correctly.
I want it to show the number of days and hours left.
And another problem that exists is that the counting speed is very high and it is not compatible with real time

2

Answers


  1. Please do edit the timediff variable to the following in order to get the remaining days:

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

    In order to get the remaining days, please do use the following way:

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

    In order match the speed of the realtime. Please do use the Timer.Periodic() method available in flutter. Which provides a option of callback exposed where you can handle the BL for the application.

    Login or Signup to reply.
  2. start timer in initState.

    @override
          void initState() {
             timer = Timer.periodic(duration, (Timer t) {
              handleTick();
            });
            super.initState();
          }
    

    what happening in your code is timer variable is getting assigned Timer multiple time. causing multiple function call for handleTick().
    like when SetState() is called in handleTick() method it trigger the build method to be called and whole widget get rebuilt.

    @override
      Widget build(BuildContext context) {
        timer = Timer.periodic(duration, (Timer t) {
          handleTick();
        });
         .....
    
         return ...;
       }
    

    but here timer get a new Timer.periodic() assigned

        timer = Timer.periodic(duration, (Timer t) {
          handleTick();
        });
    

    but old Timer.periodic() is still running and handleTick() is being called and timeDiff is keep decreasing and after Timer.periodic() will be assigned to timer variable causing all timer running in parallel and also calling handleTick() multiple times
    instead of every 1 second.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search