Is there a way to make a CircularProgressIndicator or Future last a minimum amount of time (when making a HTTP request)?

Viewed 1000

For context, suppose I have Flutter code which displays a CircularProgressIndicator while code is being fetched from an API:

Future<void> getItems() async {
  setState(ViewState.Busy);
  items = await _api.getItems();
  setState(ViewState.Idle);
}

So that the CircularProgressIndicator does not display for only a fraction of a second (which I find disrupts the flow of related animations), I want to make this indicator display for a minimum amount of time.

I think I can solve this problem using the Future API or a timer, by somehow setting the minimum amount of time a HTTP request future can take. How can I go about achieving this?

4 Answers

I use this pattern frequently. Future-wait accept a list of Futures. It executes them all in parallel and returns will all have completed. I think it looks much cleaner.

https://api.dartlang.org/stable/2.3.1/dart-async/Future/wait.html

  List<Future> futures = [];
  futures.add(Future.delayed(Duration(seconds: 1)));
  futures.add(_api.getItems());
  await Future.wait(futures);

Simplest idea would be to add booleans which check if both the timer and response have executed

Future<void> getItems() async {

  setState(ViewState.Busy);

  bool gotResponse = false;
  bool timerExpired = false;

  Future.delayed(Duration(seconds: 1)).then((_) {
    timerExpired = true;
    if (gotResponse) setState(ViewState.Idle);
  });

  items = await _api.getItems().then((items) {
    gotResponse = true;
    if (timerExpired) setState(ViewState.Idle);
  });

}

The basic idea is to call setState(ViewState.Idle) only if both Async operations have completed and corresponding bools are true

You can do this in your getTimes function:

Future<void> getItems() async {
  setState(ViewState.Busy);
  await Future.delayed(Duration(seconds: amountOfSeconds));
  items = await _api.getItems();
  setState(ViewState.Idle);
}

Here it will wait x amount of seconds.

I hope this will help.

I created and use the following extension method for this purpose:

extension FutureExtensions<T> on Future<T> {
  Future<T> withMinDuration({
    Duration duration = const Duration(milliseconds: 400),
  }) async {
    final delayFuture = Future<void>.delayed(duration);
    await Future.wait([this, delayFuture]);
    return this;
  }
}
Related