Flutter中快速切换TabBar时showDialog加载弹窗无法消失求助
Flutter TabBar快速切换后加载弹窗无法消失的解决方案
问题根源
- 快速切换Tab时,多次触发
showWaiting生成叠加弹窗,但Success状态仅执行一次pop,导致残留弹窗无法关闭。 FirstWidget未监听Bloc状态变化,FirstTab触发的请求完成后,无对应逻辑关闭弹窗,仅切换到SecondTab时才处理状态,但此时可能context已失效或状态已错过。showWaiting使用当前Widget的context,切换Tab后该context对应的导航栈不再活跃,后续pop无法正确关闭弹窗。
解决方案
1. 统一使用根导航器管理弹窗
修改showWaiting方法,挂载弹窗到根导航栈,不受Tab切换影响:
Future<void> showWaiting(BuildContext context) { return showDialog( context: context, useRootNavigator: true, // 绑定根导航器 barrierDismissible: false, // 禁止手动关闭弹窗 builder: (BuildContext context) => Container( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, color: Colors.black.withOpacity(0.5), child: const Center( child: CircularProgressIndicator( strokeWidth: 1, color: Colors.black, backgroundColor: Colors.white, ), ), ) ); }
2. 在FirstWidget中添加Bloc状态监听
让FirstWidget也监听Bloc状态,确保在当前Tab就能处理弹窗关闭:
class _FirstWidgetState extends State<FirstWidget> { late StatisticsCubit _cubit; bool _isLoading = false; // 本地跟踪加载状态,避免重复触发 @override void initState() { super.initState(); _cubit = BlocProvider.of<StatisticsCubit>(context); } @override Widget build(BuildContext context) { return BlocListener<StatisticsCubit, StatisticsState>( listener: (context, state) { if (state is Success) { setState(() => _isLoading = false); Navigator.of(context, rootNavigator: true).pop(); } if (state is Waiting) { setState(() => _isLoading = true); } }, child: TabBar( onTap: (index) async { if (index == 0 && !_isLoading) { final connectivityResult = await (Connectivity().checkConnectivity()); if (connectivityResult == ConnectivityResult.wifi || connectivityResult == ConnectivityResult.ethernet) { setState(() => _isLoading = true); showWaiting(context); _cubit.getData(); } } }, tabs: [ Tab( icon: SizedBox( width: 60.w, child: Column( children: [ Text( "First", style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, height: 1, color: Colors.white ), ), ], ), ), ), Tab( icon: SizedBox( width: 60.w, child: Column( children: [ Text( "Second", style: TextStyle( fontSize: 14.sp, fontWeight: FontWeight.w500, height: 1, color: Colors.white ), ), ], ), ), ) ], ), ); } }
3. 统一Bloc状态触发逻辑
将弹窗显示逻辑移到Bloc状态监听中,避免在onTap中直接调用:
// StatisticsCubit中修改getData方法 void getData() async { emit(Waiting()); try { // 数据获取逻辑 final data = await fetchData(); emit(Success(data)); } catch (e) { emit(Failure(e)); } }
然后在所有监听Widget中统一处理:
// FirstWidget和SecondWidget的BlocListener统一逻辑 listener: (context, state) { if (state is Waiting && !_isLoading) { showWaiting(context); setState(() => _isLoading = true); } if (state is Success || state is Failure) { setState(() => _isLoading = false); Navigator.of(context, rootNavigator: true).pop(); } },
内容的提问来源于stack exchange,提问作者newbie2210
相关产品推荐
相关产品推荐

