How and why to write your own linear progress widget in flutter?

Reading time: 2 minutes

Flutter provides CircularProgressIndicator and LinearProgressIndicator to show users that we are waiting for some action to complete. If we want to provide users with information on how long it will take to wait we’ll have to update the state of those indicators outside.

What if want simple countdown progress view, without any additional work, than code below can be useful for you:

import 'package:flutter/material.dart';

class SecondsLinearProgress extends StatefulWidget {
  final timeout;
  final _total;

  SecondsLinearProgress(this._total, {this.timeout});

  @override
  _SecondsLinearProgressState createState() => _SecondsLinearProgressState(timeout != null ? timeout : _total, _total);
}

class _SecondsLinearProgressState extends State<SecondsLinearProgress> with SingleTickerProviderStateMixin {
  AnimationController controller;
  Animation<double> animation;
  int _timeout;
  int _total;

  _SecondsLinearProgressState(this._timeout, this._total);

  @override
  void initState() {
    super.initState();
    controller = AnimationController(duration: Duration(seconds: _timeout), vsync: this);
    animation = Tween(begin: _timeout.toDouble() / _total.toDouble(), end: 0.0).animate(controller)
      ..addListener(() {
        setState(() {});
      });
    controller.forward();
  }

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

  @override
  Widget build(BuildContext context) {
    return new Container(
      child: LinearProgressIndicator(
        value: animation.value,
        backgroundColor: Colors.black26,
        valueColor: AlwaysStoppedAnimation<Color>(Colors.white),
      ),
    );
  }
}

As you can see we animate progress internally, pass total seconds to wait, and timeout if we don’t start from 0s.

Here goes two examples:

class ExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        backgroundColor: Colors.blueAccent,
        appBar: AppBar(
          title: Text("Progress"),
        ),
        body: Center(
          child: Column(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: [
              SecondsLinearProgress(30),
              SecondsLinearProgress(30, timeout: 20),
            ],
          ),
        ));
  }
}

And result will be:

I’ve used this widget to wait for users that should respond to question with a fixed time limit. You can use it with parents that get constantly rebuild, but don’t forget to pass the correct timeout where it should continue from.

Leave a Reply

Your email address will not be published. Required fields are marked *