Last active
May 29, 2022 04:55
-
-
Save fabiancrx/5a95147c9dc1feda1627461ad07803e0 to your computer and use it in GitHub Desktop.
Example of a flutter app displaying a global loading Indicator
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'package:flutter/material.dart'; | |
import 'package:flutter_riverpod/flutter_riverpod.dart'; | |
final loadingProvider = StateProvider<bool>((ref) => false); | |
void main() => runApp(const ProviderScope(child: MaterialApp(home: GlobalLoadingIndicator(child: Home())))); | |
class Home extends ConsumerWidget { | |
const Home({Key? key}) : super(key: key); | |
@override | |
Widget build(BuildContext context, ref) { | |
final isLoading = ref.watch(loadingProvider); | |
return Scaffold( | |
appBar: AppBar(), | |
body: Center( | |
child: SwitchListTile( | |
value: isLoading, | |
onChanged: (value) { | |
ref.read(loadingProvider.notifier).state = value; | |
Future.delayed(const Duration(seconds: 4)).then((value) { | |
ref.read(loadingProvider.notifier).state = false; | |
}); | |
}, | |
title: const FlutterLogo(), | |
), | |
)); | |
} | |
} | |
// This widget should wrap your entire app, but be below MaterialApp in order to have access to the Overlay | |
class GlobalLoadingIndicator extends ConsumerStatefulWidget { | |
final Widget child; | |
const GlobalLoadingIndicator({required this.child, Key? key}) : super(key: key); | |
@override | |
ConsumerState createState() => _GlobalLoadingIndicatorState(); | |
} | |
class _GlobalLoadingIndicatorState extends ConsumerState<GlobalLoadingIndicator> { | |
//We need to cache the overlay entries we are showing as part of the indicator in order to remove them when the indicator is hidden. | |
final List<OverlayEntry> _entries = []; | |
@override | |
Widget build(BuildContext context) { | |
ref.listen<bool>(loadingProvider, (previous, next) { | |
// We just want to make changes if the states are different | |
if (previous == next) return; | |
if (next) { | |
// Add a modal barrier so the user cannot interact with the app while the loading indicator is visible | |
_entries.add(OverlayEntry(builder: (_) => ModalBarrier(color: Colors.black12.withOpacity(.5)))); | |
_entries.add(OverlayEntry( | |
builder: (_) =>const Center( | |
child: Card(child: Padding(padding: EdgeInsets.all(16.0), child: CircularProgressIndicator()))))); | |
// Insert the overlay entries into the overlay to actually show the loading indicator | |
Overlay.of(context)?.insertAll(_entries); | |
} else { | |
// Remove the overlay entries from the overlay to hide the loading indicator | |
_entries.forEach((e) => e.remove()); | |
// Remove the cached overlay entries from the widget state | |
_entries.clear(); | |
} | |
}); | |
return widget.child; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment