【问题标题】:How to make go_router, Appbar, and Drawer work together in Flutter?如何让go_router、Appbar、Drawer在Flutter中协同工作?
【发布时间】:2023-01-04 02:27:14
【问题描述】:

我在 Flutter 中使用 go_router 包进行应用程序路由,但是当我将它与默认的 Flutter Appbar 和 Drawer 小部件一起使用时遇到了问题。

  • 我通过单击抽屉调用的典型“go”和“push”方法在按下后退按钮时无法按预期工作。
  • AppBar 不暗示前导返回或菜单行为。

是否需要做一些特别的事情才能让 go_router 与 Flutter Navigator 很好地配合使用?也许我需要设置一些特定的字段或全局键?

这是我的设置的样子:

class MainApp extends ConsumerStatefulWidget {
  const MainApp({Key? key}) : super(key: key);

  @override
  ConsumerState<MainApp> createState() => _MainAppState();
}

class _MainAppState extends ConsumerState<MainApp> {
  late GoRouter router;
  late Future<void> jwtInit;

  @override
  void initState() {
    jwtInit = ref.read(jwtProvider.notifier).init();

    router = GoRouter(
      routes: [
        GoRoute(
          path: "/",
          name: "home",
          pageBuilder: (context, state) => MaterialPage<void>(
            key: state.pageKey,
            child: const HomeScreen(),
          ),
        ),
        GoRoute(
          path: "/settings",
          name: "settings",
          pageBuilder: (context, state) => MaterialPage<void>(
            key: state.pageKey,
            child: const SettingsScreen(),
          ),
        ),
        GoRoute(
          path: "/programs",
          name: "programs",
          pageBuilder: (context, state) => MaterialPage<void>(
            key: state.pageKey,
            child: const ProgramScreen(),
          ),
        ),
        GoRoute(
          path: "/programs/:programId",
          name: "program",
          pageBuilder: (context, state) => MaterialPage<void>(
            key: state.pageKey,
            child: ProgramDetailsScreen(
              // programId: 39,
              programId: int.parse(state.params["programId"]!),
            ),
          ),
        ),
        GoRoute(
            path: "/activity/:activityId",
            name: "activity",
            pageBuilder: (context, state) {
              return MaterialPage<void>(
                key: state.pageKey,
                child: ActivityScreen(
                  id: int.parse(state.params["activityId"]!),
                ),
              );
            }),
        GoRoute(
          path: "/login",
          name: "login",
          pageBuilder: (context, state) => MaterialPage<void>(
            key: state.pageKey,
            child: const LoginScreen(),
          ),
        ),
      ],
      errorPageBuilder: (context, state) => MaterialPage<void>(
        key: state.pageKey,
        child: const Scaffold(
          body: Center(
            child: Text("PAGE NOT FOUND!"),
          ),
        ),
      ),
      // refreshListenable: api,
      redirect: (context, state) {
        final loggedIn = ref.read(jwtProvider.notifier).isLoggedIn;
        final goingToLogin = state.location == '/login';

        // the user is not logged in and not headed to /login, they need to login
        if (!loggedIn && !goingToLogin) return '/login';

        // the user is logged in and headed to /login, no need to login again
        if (loggedIn && goingToLogin) return '/';

        // no need to redirect - go to intended page
        return null;
      },
    );
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    //The reason for this FutureBuilder is to wait for the api key to
    //load from storage before allowing the initial page to route. Otherwise
    //the routing goes too fast and it looks logged out.
    return FutureBuilder(
        future: jwtInit,
        builder: (context, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            //Run the UI
            return MaterialApp.router(
              debugShowCheckedModeBanner: false,
              title: 'MyApp',
              theme: MyTheme.darkTheme(context),
              routeInformationProvider: router.routeInformationProvider,
              routeInformationParser: router.routeInformationParser,
              routerDelegate: router.routerDelegate,
            );
          } else {
            return Container();
          }
        });
  }
}

在我的抽屉里,我这样调用导航:

onTap: () {
  context.push("/settings");
}

【问题讨论】:

  • 通常在主页中使用Drawer,你试过context.push("/")吗?这个对我有用。

标签: flutter flutter-navigation flutter-routes flutter-go-router


【解决方案1】:

使用ShellRouterGoRouter来满足您的要求!


例子:

路由器

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

final router = GoRouter(
  initialLocation: '/',
  navigatorKey: _rootNavigatorKey,
  routes: [
    ShellRoute(
      navigatorKey: _shellNavigatorKey,
      pageBuilder: (context, state, child) {
        print(state.location);
        return NoTransitionPage(
            child: ScaffoldAppAndBottomBar(child: child));
      },
      routes: [
        GoRoute(
          parentNavigatorKey: _shellNavigatorKey,
          path: '/home',
          pageBuilder: (context, state) {
            return NoTransitionPage(
              child: Scaffold(
                body: const Center(
                  child: Text("Home"),
                ),
              ),
            );
          },
        ),
        GoRoute(
          path: '/',
          parentNavigatorKey: _shellNavigatorKey,
          pageBuilder: (context, state) {
            return const NoTransitionPage(
              child: Scaffold(
                body: Center(child: Text("Initial")),
              ),
            );
          },
        ),
      ],
    ),
  ],
);

脚手架AppAndBottomBar

class ScaffoldAppAndBottomBar extends StatelessWidget {
  Widget child;
  ScaffoldAppAndBottomBar({super.key, required this.child});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: AppBar(
          centerTitle: true,
          title: const Text(
            "App Bar",
          ),
          backgroundColor: Colors.amber,
        ),
        body: SafeArea(child: child),
        bottomNavigationBar: Container(
          color: Colors.blue,
          height: 56,
          width: double.infinity,
          child: const Center(child: Text("Bottom Navigation Bar")),
        ),
        floatingActionButton: FloatingActionButton(
          backgroundColor: Colors.red,
          onPressed: () {
            context.go('/home');
          },
          child: const Icon(Icons.home),
        ));
  }
}

输出:

最初

按下浮动按钮后


使用ShellRouteGoRouterhere参考底部导航栏的详细代码和解释

【讨论】:

    猜你喜欢
    • 2019-01-04
    • 2021-12-29
    • 2020-01-17
    • 2017-11-15
    • 2020-01-13
    • 2014-11-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多