如何在 go router flutter 中导航到 shell 路由?

问题描述 投票:0回答:2

我正在使用 Go Router 6.2.0 和 Flutter 3.7.3

问题:我想在用户登录时导航到shell路由,在没有人登录时导航到登录页面。 开发人员通常做的是在用户登录时将路由重定向到另一个路由,但我无法将路由重定向到 shell 路由,因为我不知道怎么做

我的 GoRouter 中有 2 条路线,1 条是登录页面的登录路线,在我的登录页面中,我这样做是为了检查身份验证,然后相应地转到另一条路线:

  Scaffold(
      body: StreamBuilder(
          stream: FirebaseAuth.instance.authStateChanges(),
          builder: (context, snapshot) {
            if (snapshot.connectionState == ConnectionState.active) {
              final user = snapshot.data;
              if (user != null) {
                GoRouter.of(context).go(NavigationRailScreen.routeName);
              }
            }
            return Center(
              child: SizedBox(
                width: 400,
                child: ui.SignInScreen(
                  providers: [ui.EmailAuthProvider()],
                  actions: [
                    ui.AuthStateChangeAction<ui.SignedIn>((context, state) {
                      GoRouter.of(context).go(NavigationRailScreen.routeName);
                    }),
                  ],
                ),
              ),
            );
          }),
    );

第二条路线是 NavigationRail,它包含我的所有其他路线

final GlobalKey<NavigatorState> _rootNavigator = GlobalKey(debugLabel: 'root');
final GlobalKey<NavigatorState> _shellNavigator =
    GlobalKey(debugLabel: 'shell');

GoRouter router = GoRouter(
  navigatorKey: _rootNavigator,
  initialLocation: '/',
  routes: [
    GoRoute(
      parentNavigatorKey: _rootNavigator,
      path: '/',
      name: 'login',
      builder: (context, state) => AppLoginScreen(key: state.pageKey),
    ),
    ShellRoute(
        navigatorKey: _shellNavigator,
        builder: (context, state, child) =>
            NavigationRailScreen(key: state.pageKey, child: child),
        routes: [
          GoRoute(
            path: '/',
            name: HomeScreen.routeName,
            pageBuilder: (context, state) {
              return NoTransitionPage(child: HomeScreen(key: state.pageKey));
            },
          ),
          GoRoute(
              path: '/restaurants',
              name: RestaurantsScreen.routeName,
              pageBuilder: (context, state) {
                return NoTransitionPage(
                    child: RestaurantsScreen(key: state.pageKey));
              },
              routes: [
                GoRoute(
                  parentNavigatorKey: _shellNavigator,
                  path: ':id',
                  name: RestaurantDetailsScreen.routeName,
                  pageBuilder: (context, state) {
                    final String id = state.params['id'] as String;
                    return NoTransitionPage(
                      child:
                          RestaurantDetailsScreen(id: id, key: state.pageKey),
                    );
                  },
                  routes: [
                    GoRoute(
                      parentNavigatorKey: _shellNavigator,
                      path: AddRestaurantReviewScreen.routeName,
                      name: AddRestaurantReviewScreen.routeName,
                      pageBuilder: (context, state) {
                        final String id = state.params['id'] as String;
                        return NoTransitionPage(
                          child: AddRestaurantReviewScreen(
                              key: state.pageKey, id: id),
                        );
                      },
                    ),
                    GoRoute(
                        name: MenuItemsScreen.routeName,
                        path: MenuItemsScreen.routeName,
                        pageBuilder: (context, state) {
                          return NoTransitionPage(
                            child: MenuItemsScreen(
                                key: state.pageKey, id: state.params['id']!),
                          );
                        },
                        routes: [
                          GoRoute(
                              name: MenuItemDetailsScreen.routeName,
                              path: ':menuItemId',
                              pageBuilder: (context, state) {
                                final String id =
                                    state.params['menuItemId'] as String;
                                final String restaurantId =
                                    state.params['id'] as String;
                                return NoTransitionPage(
                                  child: MenuItemDetailsScreen(
                                    key: state.pageKey,
                                    id: id,
                                    restaurantId: restaurantId,
                                  ),
                                );
                              },
                              routes: [
                                GoRoute(
                                    name: AddMenuItemReviewScreen.routeName,
                                    path: AddMenuItemReviewScreen.routeName,
                                    pageBuilder: (context, state) {
                                      final String id =
                                          state.params['menuItemId'] as String;
                                      final String restaurantId =
                                          state.params['id'] as String;

                                      return NoTransitionPage(
                                          child: AddMenuItemReviewScreen(
                                        key: state.pageKey,
                                        id: id,
                                        restaurantId: restaurantId,
                                      ));
                                    })
                              ]),
                        ]),
                  ],
                ),
              ]),
          GoRoute(
            path: '/profile',
            name: UserProfileScreen.routeName,
            pageBuilder: (context, state) {
              return NoTransitionPage(
                  child: UserProfileScreen(key: state.pageKey));
            },
          )
        ])
  ],
  errorBuilder: (context, state) => RouteErrorScreen(
    errorMsg: state.error.toString(),
    key: state.pageKey,
  ),
);
flutter dart navigation router flutter-go-router
2个回答
0
投票

要导航到 shell 路由,下面给出代码用您的路由名称替换位置

  GoRouter router = GoRouter.of(context);
              router.go(location);

为了处理身份验证,我使用了 go router 的重定向方法 其中发出当前 appstatus 的状态。

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

GoRouter gorouter(AppStatus appStatus) {
  return GoRouter(
    initialLocation: RouteConstants.login,
    navigatorKey: _rootNavigatorKey,
    redirect: (BuildContext context, GoRouterState state) {
      switch (appStatus) {
        case AppStatus.unauthenticated:
          return RouteConstants.login;
        case AppStatus.authenticated:
          if (state.location == RouteConstants.login ||
              state.location == RouteConstants.signUp) {
            return RouteConstants.dashboard;
          } else {
            return state.location;
          }
      }
    },
    routes: [
      ShellRoute(
        navigatorKey: _shellNavigatorKey,
        pageBuilder: (context, state, child) {
          return NoTransitionPage(
              child: App(
            location: state.location,
            child: child,
          ));
        },
        routes: [
          GoRoute(
            path: RouteConstants.dashboard,
            parentNavigatorKey: _shellNavigatorKey,
            pageBuilder: (context, state) {
              return const NoTransitionPage(child: Dashboard());
            },
          ),
          GoRoute(
            path: RouteConstants.history,
            parentNavigatorKey: _shellNavigatorKey,
            pageBuilder: (context, state) {
              return const NoTransitionPage(child: History());
            },
          ),
        ],
      ),
      GoRoute(
        parentNavigatorKey: _rootNavigatorKey,
        path: RouteConstants.login,
        builder: (context, state) {
          return const SignInScreen();
        },
      ),
      GoRoute(
        parentNavigatorKey: _rootNavigatorKey,
        path: RouteConstants.signUp,
        builder: (context, state) {
          return const SignUpScreen();
        },
      ),
    ],
  );
}

主屏幕

class AppView extends StatelessWidget {
  const AppView({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      debugShowCheckedModeBanner: false,
      title: 'Lazy Us',
      theme: lightTheme(),
      darkTheme: darkTheme(),
      routerConfig: gorouter(
        context.select((AppBloc bloc) => bloc.state.status),
      ),
    );
  }
}

0
投票

我花了几个小时试图解决这个问题,我认为目前无法使用 GoRoute 导航到 shell 路由,但是我能够根据我正在工作的项目找到适合我的方法在。请检查以下代码:

  1. 首先,我将底部导航栏添加到我的路线常量中。

      static const onboarding = '/';
      static const navigationBar = '/navigationBar';
      static const home = '/home';
      static const unknown = '/unknown';
      static const notifications = '/notifications';
      }```
    
    
  2. 其次,我创建了 BottomNavigationScreen。

      final Widget? child;
      const BottomNavigationScreen({super.key, this.child});
    
      @override
      State<BottomNavigationScreen> createState() => _BottomNavigationScreenState();
    }
    
    class _BottomNavigationScreenState extends State<BottomNavigationScreen> {
      int selectedIndex = 0;
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: widget.child,
          bottomNavigationBar: BottomNavigationBar(
              currentIndex: calculateSelectedIndex(),
              onTap: (value) => setState(() {
                    selectedIndex = value;
                    switch (value) {
                      case 0:
                        return context.go(AppRoutes.home);
                      case 1:
                        return context.go(AppRoutes.unknown);
                      case 2:
                        return context.go(AppRoutes.notifications);
                      case 3:
                        return context.go(AppRoutes.profile);
                    }
                  }),
              type: BottomNavigationBarType.fixed,
              items: List.generate(
                  items.length,
                  (i) => BottomNavigationBarItem(
                      icon: Icon(
                        items[i],
                        size: 30,
                        color: selectedIndex == i
                            ? const Color(0xff5B53FF)
                            : Colors.black,
                      ),
                      label: ''))),
        );
      }
    
      int calculateSelectedIndex() {
        final location = GoRouter.of(context).location;
        switch (location) {
          case AppRoutes.home:
            return 0;
          case AppRoutes.unknown:
            return 1;
          case AppRoutes.notifications:
            return 2;
          case AppRoutes.profile:
            return 3;
          default:
            return 0;
        }
      }
    }
    
    List<IconData> items = [
      Icons.house,
      Icons.confirmation_num_rounded,
      Icons.notifications,
      Icons.account_circle
    ];```
    
    
    
  3. 第三,我定义了我的 shell 路由并注意到我还在路由中添加了 BottomNavigationScreen 并给它和初始屏幕来显示。这是我使用的技巧。

GoRoute(
       path: AppRoutes.personalInfoScreen3,
       builder: (context, state) => const PersonalInfoScreen3(),
     ),
     GoRoute(
       path: AppRoutes.navigationBar,
       builder: (context, state) =>
           const BottomNavigationScreen(child: HomeScreen()),
     ),
     ShellRoute(
         navigatorKey: _shellNavigatorKey,
         builder: (context, state, child) =>
             BottomNavigationScreen(child: child),
         routes: [
           GoRoute(
             path: AppRoutes.home,
             builder: (context, state) => const HomeScreen(),
           ),
           GoRoute(
             path: AppRoutes.unknown,
             builder: (context, state) => const Scaffold(),
           ),
           GoRoute(
             path: AppRoutes.notifications,
             builder: (context, state) => const NotificationScreen(),
           ),
           GoRoute(
             path: AppRoutes.profile,
             builder: (context, state) => const ProfileScreen(),
           ),
         ])
  1. 最后,我们可以在注册或登录应用程序后导航到 BottomNavigationScreen。
CustomButton(onPressed: () => context.push(AppRoutes.navigationBar),
              text: 'Continue',
              color: secondaryColor),
© www.soinside.com 2019 - 2024. All rights reserved.