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

如何在Flutter中使用Go Router实现API请求时的加载弹窗?

使用Go Router实现导航前加载对话框

在需要先调用API获取路由路径再跳转的场景下,你可以通过在导航逻辑中嵌入加载状态管理来实现,核心是先触发加载对话框,完成API请求后再执行导航操作。以下是具体实现步骤:

1. 基础Go Router配置

先确保你已经配置好基础的Go Router实例,示例如下:

final GoRouter _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
    ),
    GoRoute(
      path: '/details/:id',
      builder: (context, state) => DetailsScreen(id: state.pathParameters['id']!),
    ),
  ],
);

2. 实现带加载状态的导航逻辑

在触发导航的按钮或操作中,按以下流程处理:

  • 显示加载对话框
  • 异步调用API获取目标路由
  • 根据API结果执行导航或错误处理
  • 关闭加载对话框

示例代码:

ElevatedButton(
  onPressed: () async {
    // 1. 显示加载对话框
    showDialog(
      context: context,
      barrierDismissible: false, // 禁止点击外部关闭
      builder: (context) => const Center(
        child: CircularProgressIndicator(),
      ),
    );

    try {
      // 2. 调用API获取路由路径
      final String targetRoute = await _fetchRouteFromApi();
      
      // 3. 关闭对话框并跳转
      Navigator.of(context).pop(); // 关闭加载框
      context.go(targetRoute); // 使用Go Router导航
    } catch (e) {
      // 4. 处理错误:关闭对话框并提示
      Navigator.of(context).pop();
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('获取路由失败: $e')),
      );
    }
  },
  child: const Text('跳转至目标页面'),
);

// 模拟API请求方法
Future<String> _fetchRouteFromApi() async {
  await Future.delayed(const Duration(seconds: 2)); // 模拟网络延迟
  // 假设API返回的路由是'/details/123'
  return '/details/123';
}

3. 优化方案:封装通用导航方法

如果多个地方需要类似逻辑,可以封装成通用方法,避免重复代码:

Future<void> navigateWithLoading(BuildContext context, Future<String> Function() fetchRoute) async {
  showDialog(
    context: context,
    barrierDismissible: false,
    builder: (context) => const Center(child: CircularProgressIndicator()),
  );

  try {
    final route = await fetchRoute();
    Navigator.of(context).pop();
    context.go(route);
  } catch (e) {
    Navigator.of(context).pop();
    ScaffoldMessenger.of(context).showSnackBar(
      SnackBar(content: Text('导航失败: $e')),
    );
  }
}

// 使用时:
ElevatedButton(
  onPressed: () => navigateWithLoading(context, _fetchRouteFromApi),
  child: const Text('跳转'),
);

4. 进阶:结合状态管理(可选)

如果你的项目使用状态管理库(如Riverpod、Provider),可以将加载状态提升到全局状态,让UI更灵活响应:

  • 在状态类中维护isLoading变量
  • 触发导航时设置isLoading = true,请求完成后设为false
  • 在UI层根据isLoading显示加载对话框或正常内容

示例(Riverpod):

final navigationProvider = StateNotifierProvider<NavigationNotifier, bool>((ref) {
  return NavigationNotifier();
});

class NavigationNotifier extends StateNotifier<bool> {
  NavigationNotifier() : super(false);

  Future<void> navigate(BuildContext context) async {
    state = true;
    try {
      final route = await _fetchRouteFromApi();
      context.go(route);
    } catch (e) {
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(e.toString())));
    } finally {
      state = false;
    }
  }
}

// UI层监听状态显示对话框
Consumer(
  builder: (context, ref, child) {
    final isLoading = ref.watch(navigationProvider);
    if (isLoading) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        showDialog(
          context: context,
          barrierDismissible: false,
          builder: (context) => const Center(child: CircularProgressIndicator()),
        );
      });
    } else {
      // 如果对话框存在,关闭它
      Navigator.of(context, rootNavigator: true).popUntil((route) => !route.isDialog);
    }
    return ElevatedButton(
      onPressed: () => ref.read(navigationProvider.notifier).navigate(context),
      child: const Text('跳转'),
    );
  },
)

内容的提问来源于stack exchange,提问作者yadhu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 06:35:17