使用 ShellRoute 和 GoRouter 5.0 在选项卡之间切换时如何返回嵌套路由?

biz*_*z84 17 dart flutter flutter-go-router

ShellRouteI\xe2\x80\x99m 尝试在 go_router 5.0 中使用嵌套导航。

\n

如下例所示,单击产品时我可以正确导航到(嵌套)产品页面。

\n

但是,如果我切换到购物车选项卡并返回到产品,我将返回到(根)产品页面而不是(嵌套)产品页面:

\n

使用 GoRouter 5.0 的 ShellRoute 示例

\n

这就是我设置路由器的方式:

\n
enum AppRoute {\n  products,\n  product,\n  cart,\n  account,\n}\n\nfinal goRouter = GoRouter(\n    initialLocation: \'/products\',\n    navigatorKey: _rootNavigatorKey,\n    debugLogDiagnostics: true,\n    routes: [\n      ShellRoute(\n        navigatorKey: _shellNavigatorKey,\n        builder: (context, state, child) {\n          return ScaffoldWithBottomNavBar(child: child);\n        },\n        routes: [\n          // Products\n          GoRoute(\n            path: \'/products\',\n            name: AppRoute.products.name,\n            redirect: (context, state) {\n              print(state.toString());\n              return null;\n            },\n            pageBuilder: (context, state) => NoTransitionPage(\n              key: state.pageKey,\n              restorationId: state.pageKey.value,\n              child: const ProductsListScreen(),\n            ),\n            routes: [\n              GoRoute(\n                path: \':id\',\n                name: AppRoute.product.name,\n                pageBuilder: (context, state) {\n                  final productId = state.params[\'id\']!;\n                  // TODO: Cupertino slide transition\n                  return MaterialPage(\n                    key: state.pageKey,\n                    restorationId: state.pageKey.value,\n                    child: ProductScreen(productId: productId),\n                  );\n                },\n              ),\n            ],\n          ),\n          // Shopping Cart\n          GoRoute(\n            path: \'/cart\',\n            name: AppRoute.cart.name,\n            pageBuilder: (context, state) => NoTransitionPage(\n              key: state.pageKey,\n              child: const ShoppingCartScreen(),\n            ),\n          ),\n          // Account page\n          GoRoute(\n            path: \'/account\',\n            name: AppRoute.account.name,\n            pageBuilder: (context, state) => NoTransitionPage(\n              key: state.pageKey,\n              child: const AccountScreen(),\n            ),\n          ),\n        ],\n      ),\n    ],\n  );\n
Run Code Online (Sandbox Code Playgroud)\n

这是小部件build的方法ScaffoldWithBottomNavBar

\n
@override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      body: widget.child,\n      bottomNavigationBar: BottomNavigationBar(\n        type: BottomNavigationBarType.fixed,\n        unselectedItemColor: Colors.grey,\n        selectedItemColor: Colors.black87,\n        currentIndex: _selectedIndex,\n        items: [\n          BottomNavigationBarItem(\n            icon: const Icon(\n              Icons.list,\n            ),\n            label: \'Products\'.hardcoded,\n          ),\n          BottomNavigationBarItem(\n            icon: const ShoppingCartIcon(),\n            label: \'Cart\'.hardcoded,\n          ),\n          BottomNavigationBarItem(\n            icon: const Icon(\n              Icons.account_circle,\n            ),\n            label: \'Account\'.hardcoded,\n          ),\n        ],\n        onTap: (index) => _tap(context, index),\n      ),\n    );\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

在选项卡按钮回调中,我这样做:

\n
  void _tap(BuildContext context, int index) {\n    setState(() => _selectedIndex = index); // used for the highlighted state\n    // navigate to the target route based on the tab index\n    if (index == 0) {\n      context.goNamed(AppRoute.products.name);\n    } else if (index == 1) {\n      context.goNamed(AppRoute.cart.name);\n    } else if (index == 2) {\n      context.goNamed(AppRoute.account.name);\n    }\n  }\n
Run Code Online (Sandbox Code Playgroud)\n

我明白为什么这不起作用,因为我\xe2\x80\x99m 告诉 GoRouter转到ShellRoute.

\n

理想情况下,我想要一种通过索引切换到特定选项卡的方法,并且让 GoRouter“记住”它是否位于嵌套或顶级路由上。

\n

请注意,与 不同的是TabBarBottomNavigationBar没有可以用来切换索引的控制器。

\n

GoRouter 5.0 是新的,没有太多文档或示例来展示此类常见用例。

\n

有人知道如何解决这个问题吗?

\n

注意:我的想法之一是将选定的产品 ID 作为应用程序状态存储在某处,并在路由redirect内的函数内使用它/products,但是知道我应该在哪里将该状态重置为变得很复杂null,并且我的实验NavigationObserver没有产生结果想要的结果。

\n

2023 年 6 月 28 日更新

\n

GoRouter 7.1.0添加了一个新StatefulShellRoute类来支持这一点。

\n

我已经写了一个完整的教程来解释如何使用它:

\n\n

小智 6

遗憾的是,这是使其成为完美路由器所缺少的一部分。正如您所注意到的,这是要跟踪的问题,并且团队已经在处理它: https: //github.com/flutter/flutter/issues/99124