You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter中快速切换TabBar时showDialog加载弹窗无法消失求助

Flutter TabBar快速切换后加载弹窗无法消失的解决方案

问题根源

  1. 快速切换Tab时,多次触发showWaiting生成叠加弹窗,但Success状态仅执行一次pop,导致残留弹窗无法关闭。
  2. FirstWidget未监听Bloc状态变化,FirstTab触发的请求完成后,无对应逻辑关闭弹窗,仅切换到SecondTab时才处理状态,但此时可能context已失效或状态已错过。
  3. 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 12:54:59