Flutter Riverpod, how to set minimut loading state time?

523 views Asked by At

Building an app with Flutter and Riverpod, using a lot of:

ref.watch(someProvider).when(data: (someData){
   // render layout with data
}, error: (err, stack) { 
  // do stuff with error
}, loading: (){
  return LoadingScreen(); <----
})

The problem is that in most cases the loading screen only renders for a split second, causing a bad experience where the app feels a little "jumpy". I would like to be able to set a minimum of say 2 seconds for the loading state, is it possible to force a widget to stay rendered for a minimum amount of time some how?

2

There are 2 answers

1
Tom Shen On

I have 2 suggestions for you :

Option A - You can put a delay of say 2 seconds in your provider, somewhere between loading and the next state. This way you make the loading screen visible at least 2 seconds.

Option B - You can also make a loadingScreen as an overlay Widget, which dismisses itself after say 2 seconds. This way you make the loading screen visible exactly 2 seconds.

I believe either way is fine in your case, since you say it flashes, I assume no heavy/long tasks are done in between states. In case you do need heavy/long tasks, option A guarantees the tasks are finished before loading screen disappears.

1
Md. Yeasin Sheikh On

You can create Stopwatch to track (approximate) operation duration. This example will give you some idea.

final someProvider = FutureProvider<int>((ref) async {
  final operationDuration = Duration(seconds: 1); //random, you can give it random to test
  final stopwatch = Stopwatch()..start();
  final data = await Future.delayed(operationDuration);

  final minOperationTime = const Duration(seconds: 2);
  final extraWaiting = minOperationTime.inMilliseconds - stopwatch.elapsed.inMilliseconds;
  if (stopwatch.elapsed.inSeconds < 2) {
    await Future.delayed(minOperationTime - stopwatch.elapsed);
  }
  return extraWaiting;
});

And widget

class LoadingTestOnFutureBuilder extends ConsumerWidget {
  const LoadingTestOnFutureBuilder({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return ref.watch(someProvider).when(data: (someData) {
      return Text("got data  ${someData}");
    }, error: (err, stack) {
      return Text("Err");
    }, loading: () {
      return CircularProgressIndicator();
    });
  }
}