Flutter - Create a countdown widget

The countdown() method should be called from the initState() method of the State object.

class _CountdownState extends State<CountdownWidget> {

  int val = 3;
  CountDown cd;

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

Description of initState() from the Flutter docs:

The framework calls initState. Subclasses of State should override initState to perform one-time initialization that depends on the BuildContext or the widget, which are available as the context and widget properties, respectively, when the initState method is called.

Here is a full working example:

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

void main() {
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
      title: 'Countdown Demo',
      theme: new ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: new MyHomePage(),
    );
  }
}


class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new CountdownWidget();
  }
}

class _CountdownState extends State<CountdownWidget> {

  int val = 3;
  CountDown cd;

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

  void countdown(){
    print("countdown() called");
    cd = new CountDown(new Duration(seconds: 4));
    StreamSubscription sub = cd.stream.listen(null);
    sub.onDone(() {
      print("Done");
    });
    sub.onData((Duration d) {
      if (val == d.inSeconds) return;
      print("onData: d.inSeconds=${d.inSeconds}");
      setState((){
        val = d.inSeconds;
      });
    });
  }

  @override
  build(BuildContext context){
    return new Scaffold(
      body: new Container(
        child: new Center(
          child: new Text(val.toString(), style: new TextStyle(fontSize: 150.0)),
        ),
      ),
    );
  }
}

class CountdownWidget extends StatefulWidget {

  @override
  _CountdownState createState() => new _CountdownState();
}

It sounds like you are trying to show an animated text widget that changes over time. I would use an AnimatedWidget with a StepTween to ensure that the countdown only shows integer values.

countdown

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    home: new MyApp(),
  ));
}

class Countdown extends AnimatedWidget {
  Countdown({ Key key, this.animation }) : super(key: key, listenable: animation);
  Animation<int> animation;

  @override
  build(BuildContext context){
    return new Text(
      animation.value.toString(),
      style: new TextStyle(fontSize: 150.0),
    );
  }
}

class MyApp extends StatefulWidget {
  State createState() => new _MyAppState();
}

class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
  AnimationController _controller;

  static const int kStartValue = 4;

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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      floatingActionButton: new FloatingActionButton(
        child: new Icon(Icons.play_arrow),
        onPressed: () => _controller.forward(from: 0.0),
      ),
      body: new Container(
        child: new Center(
          child: new Countdown(
            animation: new StepTween(
              begin: kStartValue,
              end: 0,
            ).animate(_controller),
          ),
        ),
      ),
    );
  }
}

Tags:

Dart

Flutter