Talked
Talked

Reputation: 173

How to update a Text widget automatically - Flutter

I am trying to make a simple timer to know how much time has passed from a date to a current date

but the problem I have is that the Text widget is only painted once but it does not update, and I would like the text to update every 1 second. And not have to refresh the page, is it possible to do that?

import 'package:flutter/material.dart';

class TimerPage extends StatefulWidget {
  @override
  _TimerPageState createState() => _TimerPageState();
}

class _TimerPageState extends State<TimerPage> {
  @override
  Widget build(BuildContext context) {

    final start = DateTime(2020, 8, 10, 16, 30, 0);
    final currentdate= DateTime.now();
    final comparation = currentdate.difference(start);

    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.symmetric(vertical: 20),
          child: Center(
              child: Column(
            children: <Widget>[
              Text("Start time: " + start.toString()),
              Divider(),
              Text(
                "time elapsed = " + comparation.toString().substring(0, 7),
                style: TextStyle(color: Color(0xff5abd8c), fontSize: 26),
              )
            ],
          )),
        ),
      ),
    );
  }
}

I try this:

Timer timer;
  final start = DateTime(2020, 8, 17, 21, 30, 0);
  final dateActual = DateTime.now();
  Duration comparation = new Duration(hours: 0, minutes: 0, seconds: 0);
  @override
  void initState() {
    timer = Timer.periodic(Duration(seconds: 1), (_) {
      setState(() {
        comparation = dateActual.difference(start);
        print(comparation);
      });
    });
  }

  @override
  void dispose() {
    timer?.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SafeArea(
        child: Container(
          padding: EdgeInsets.symmetric(vertical: 20),
          child: Center(
              child: Column(
            children: <Widget>[
              Text("Start time: " + start.toString()),
              Divider(),
              Text(
                "time elapsed = " + comparation.toString().substring(0, 7),
                style: TextStyle(color: Color(0xff5abd8c), fontSize: 26),
              )
            ],
          )),
        ),
      ),
    );
  }
}

Upvotes: 1

Views: 3321

Answers (1)

Christopher Moore
Christopher Moore

Reputation: 17113

To do this, you want a Timer from the dart:async library, specifically a Timer.periodic.

Instantiate one in initState of your StatefulWidget and cancel it in dispose.

Timer.periodic takes a callback that fires after every duration that's passed. Since your DateTime difference calculation is already done in build, you just need to trigger a rebuild with setState.

Timer timer;

@override
void initState() {
  timer = Timer.periodic(Duration(seconds: 1), (_) {
    setState(() {});
  });
}

@override
void dispose() {
  timer?.cancel();
}

It's not possible to do this without rebuilding, at the very least, the Text widget that's being changed. I don't think it's necessary since there isn't much in this build method, but if you wanted to do that, you would have to extract all of the necessary time calculations, timer, and single Text widget to its own StatefulWidget, so that only the one widget that's necessary to be rebuilt, is rebuilt.

Ideally, you should also be doing the time calculations outside of the build method, but it's not a huge deal in this case and you'll get something that works.

Upvotes: 3

Related Questions