Flutter中实现便捷全局加载效果的最佳实践是什么?
Flutter 实现类似 iOS AOP 加载视图的最佳实践
Flutter 里虽然没有原生 iOS 的 AOP 语法,但可以通过以下几种方案实现便捷的加载视图管理,避免重复编写显示/隐藏逻辑:
方案一:全局 Overlay 工具类(最接近 iOS 分类调用体验)
通过 Flutter 的 Overlay 组件实现全局弹窗式加载,无需依赖页面状态,直接在任意位置调用工具方法即可,和 iOS 里 [self showLoading...] 的调用方式几乎一致。
class LoadingUtil { static OverlayEntry? _overlayEntry; // 显示加载视图 static void showLoading({String title = 'processing'}) { if (_overlayEntry != null) return; // 避免重复显示 _overlayEntry = OverlayEntry( builder: (context) => Container( color: Colors.black.withOpacity(0.5), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator(color: Colors.white), const SizedBox(height: 12), Text(title, style: const TextStyle(color: Colors.white, fontSize: 16)), ], ), ), ), ); // 需要提前初始化全局 NavigatorKey,建议在 MaterialApp 里配置 Overlay.of(GlobalKey<NavigatorState>().currentContext!)?.insert(_overlayEntry!); } // 隐藏加载视图 static void hideLoading() { _overlayEntry?.remove(); _overlayEntry = null; } }
使用方式
在任意异步请求前后直接调用:
// 开始请求时显示 LoadingUtil.showLoading(title: 'processing'); // 模拟网络请求 await Future.delayed(const Duration(seconds: 2)); // 请求结束后隐藏 LoadingUtil.hideLoading();
方案二:封装页面基类(页面级加载管理)
如果需要每个页面独立管理加载状态,可以封装一个带加载逻辑的 BasePage 基类,让业务页面继承它,直接调用基类提供的加载方法。
abstract class BasePage extends StatefulWidget { const BasePage({super.key}); @override BasePageState createState() => BasePageState(); } class BasePageState extends State<BasePage> { bool _isLoading = false; String _loadingTitle = 'processing'; // 显示页面级加载 void showLoading({String title = 'processing'}) { setState(() { _isLoading = true; _loadingTitle = title; }); } // 隐藏页面级加载 void hideLoading() { setState(() { _isLoading = false; }); } // 子类实现页面主体内容 Widget buildContent(); @override Widget build(BuildContext context) { return Stack( children: [ buildContent(), // 根据加载状态显示遮罩和加载框 if (_isLoading) Container( color: Colors.black.withOpacity(0.5), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator(color: Colors.white), const SizedBox(height: 12), Text(_loadingTitle, style: const TextStyle(color: Colors.white, fontSize: 16)), ], ), ), ), ], ); } }
使用方式
业务页面继承 BasePage,实现 buildContent 方法,调用加载方法:
class HomePage extends BasePage { @override Widget buildContent() { return Scaffold( appBar: AppBar(title: const Text('Home')), body: Center( child: ElevatedButton( onPressed: () async { showLoading(title: 'loading...'); await Future.delayed(const Duration(seconds: 2)); hideLoading(); }, child: const Text('Start Request'), ), ), ); } }
方案三:结合状态管理实现全局/跨页面加载
如果需要跨页面共享加载状态(比如全局接口请求的统一加载提示),可以用 Riverpod、Provider 等状态管理工具实现。
以 Riverpod 为例:
// 定义加载状态和通知器 final loadingProvider = StateNotifierProvider<LoadingNotifier, LoadingState>((ref) => LoadingNotifier()); class LoadingState { final bool isLoading; final String title; LoadingState({required this.isLoading, this.title = 'processing'}); } class LoadingNotifier extends StateNotifier<LoadingState> { LoadingNotifier() : super(LoadingState(isLoading: false)); void showLoading({String title = 'processing'}) { state = LoadingState(isLoading: true, title: title); } void hideLoading() { state = LoadingState(isLoading: false); } }
使用方式
在页面中监听状态并显示加载视图:
class HomePage extends ConsumerWidget { const HomePage({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final loadingState = ref.watch(loadingProvider); return Scaffold( body: Stack( children: [ Center( child: ElevatedButton( onPressed: () async { ref.read(loadingProvider.notifier).showLoading(title: 'loading...'); await Future.delayed(const Duration(seconds: 2)); ref.read(loadingProvider.notifier).hideLoading(); }, child: const Text('Start Request'), ), ), if (loadingState.isLoading) Container( color: Colors.black.withOpacity(0.5), child: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator(color: Colors.white), const SizedBox(height: 12), Text(loadingState.title, style: const TextStyle(color: Colors.white, fontSize: 16)), ], ), ), ), ], ), ); } }
方案选择建议
- 追求最便捷的全局调用:选全局 Overlay 工具类
- 页面独立管理加载状态:选页面基类
- 跨页面共享加载状态或需要统一管理:选状态管理方案
内容的提问来源于stack exchange,提问作者ximmyxiao
相关产品推荐
相关产品推荐

