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

Flutter GoRouter实现Instagram式导航:StatefulShellRoute跳转难题

Flutter Instagram克隆:GoRouter导航问题解决方案

问题1:根路由无法跳转至StatefulShellBranch

直接使用GoRouter的路径或命名路由跳转即可。比如从无底部导航的登录页跳转到Feed分支:

// 直接跳转到shell分支路由
context.go('/feed');
// 或通过命名路由跳转
context.goNamed('shell_feed');

StatefulShellRoute会自动接管导航并渲染底部导航栏,无需额外处理上下文权限问题。

问题2:Profile页面推送被底部导航遮挡+代码冗余

核心思路是复用Profile页面组件与业务逻辑,避免重复定义路由与Bloc:

  1. 抽离独立的ProfilePage组件,将Bloc实例、页面逻辑封装在组件内部,或通过参数传递依赖;
  2. 同时配置两个路由入口:一个属于StatefulShellBranch(带底部导航),一个属于根路由(全屏无底部导航),两者指向同一个组件:
// 壳分支内的Profile路由(带底部导航)
GoRoute(
  path: '/profile',
  name: 'shell_profile',
  builder: (context, state) => ProfilePage(userId: state.queryParameters['userId']),
),
// 根路由的Profile(全屏无底部导航)
GoRoute(
  path: '/user_profile',
  name: 'root_profile',
  parentNavigatorKey: _rootNavigatorKey,
  builder: (context, state) => ProfilePage(userId: state.queryParameters['userId']),
),
  1. Bloc复用:如果用全局BlocProvider,直接在组件内context.read<ProfileBloc>()获取;如果是局部Bloc,可在组件初始化时创建,或通过BlocProvider.value从父级传递,确保两个路由入口共用同一个Bloc实例。

问题3:复刻Instagram导航行为(底部导航动态显示)

通过StatefulShellRoute的builder方法动态控制底部导航栏的显示:

StatefulShellRoute.indexedStack(
  navigatorKey: _shellNavigatorKey,
  builder: (context, state, navigationShell) {
    // 判断当前路由是否为根路由(非壳分支路由)
    final isRootRoute = state.matchedRoutes.every(
      (route) => !route.name?.startsWith('shell_') ?? true
    );
    return Scaffold(
      body: navigationShell,
      // 根路由场景下隐藏底部导航
      bottomNavigationBar: isRootRoute ? null : BottomNavigationBar(
        currentIndex: navigationShell.currentIndex,
        onTap: (index) => navigationShell.goBranch(index),
        items: [/* 底部导航项 */],
      ),
    );
  },
  branches: [/* 壳分支配置 */],
)

跨分支跳转时,使用navigationShell.goBranch(index)或context.goNamed('shell_xxx'),确保底部导航同步切换;需要打开全屏Profile时,跳转至根路由的/user_profile,自动隐藏底部导航。

优化后完整路由配置示例

final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();

final goRouter = GoRouter(
  navigatorKey: _rootNavigatorKey,
  initialLocation: '/feed',
  routes: [
    StatefulShellRoute.indexedStack(
      navigatorKey: _shellNavigatorKey,
      builder: (context, state, navigationShell) {
        final isRootRoute = state.matchedRoutes.every(
          (route) => !route.name?.startsWith('shell_') ?? true
        );
        return Scaffold(
          body: navigationShell,
          bottomNavigationBar: isRootRoute ? null : BottomNavigationBar(
            currentIndex: navigationShell.currentIndex,
            onTap: (index) => navigationShell.goBranch(index),
            items: const [
              BottomNavigationBarItem(icon: Icon(Icons.home), label: 'Feed'),
              BottomNavigationBarItem(icon: Icons.person, label: 'Profile'),
            ],
          ),
        );
      },
      branches: [
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/feed',
              name: 'shell_feed',
              builder: (context, state) => const FeedPage(),
            ),
          ],
        ),
        StatefulShellBranch(
          routes: [
            GoRoute(
              path: '/profile',
              name: 'shell_profile',
              builder: (context, state) => ProfilePage(
                userId: state.queryParameters['userId'] ?? 'current_user',
              ),
            ),
          ],
        ),
      ],
    ),
    GoRoute(
      path: '/user_profile',
      name: 'root_profile',
      parentNavigatorKey: _rootNavigatorKey,
      builder: (context, state) => ProfilePage(
        userId: state.queryParameters['userId'],
      ),
    ),
    // 其他根路由(如登录页)
    GoRoute(
      path: '/login',
      name: 'login',
      parentNavigatorKey: _rootNavigatorKey,
      builder: (context, state) => const LoginPage(),
    ),
  ],
);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 05:04:49