Here in this article we see how to show loading data icon with properly. We would be using StateNotifier, StateNotifierProvider with AutoDispose.
We would also be using future type for state management. Since we are going to simulate data loading from the server, we would need to be dealing with success and failure status. We would be using one bool type to do it. True would be success and false would mean failure.
Look at our widget
class CenteredIndicator extends StatelessWidget {
const CenteredIndicator({super.key});
@override
Widget build(BuildContext context) {
return const Center(
child: CircularProgressIndicator(),
);
}
}
class WidgetWithLoading extends ConsumerWidget {
const WidgetWithLoading({super.key, required this.child});
final Widget child;
@override
Widget build(BuildContext context, WidgetRef ref) {
return Stack(
children: [
child,
if (ref.watch(isLoadingProvider)) const LoadingDialog(),
],
);
}
}
final isLoadingProvider =
StateNotifierProvider.autoDispose<IsLoadingController, bool>(
(ref) => IsLoadingController(),
);
class IsLoadingController extends StateNotifier<bool> {
IsLoadingController() : super(false);
Future<T> guardFuture<T>(Future<T> Function() future) async {
state = true;
final result = await future();
state = false;
return result;
}
}
class LoadingDialog extends StatelessWidget {
const LoadingDialog({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.transparent,
body: Center(
child: Container(
alignment: Alignment.center,
width: 200,
height: 200,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
color: Theme.of(context).colorScheme.surface,
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
CircularProgressIndicator(),
SizedBox(height:20),
Text('...Processing'),
],
),
),
),
);
}
}
This is a general approach and it does not do much. Since we already defined our states in StateNotifier, and StateNotifierProvider.AutoDispose exposes the states in the ui. We need to be read them from a Widget.
The actual widget may look like below
return WidgetWithLoading(
child: Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
SomeWidget(),
ElevatedButton(
onPressed: () async {
final result =
await ref.read(isLoadingProvider.notifier).guardFuture<bool>(
() async => someFuture(),
);
if (mounted && result) {
Navigator.of(context).pop();
}
},
child: const Text('save'),
),
],
),
),
),
);