如何在同一层次结构路由中将 Shell Route 与 GoRoute 一起使用
如何使用导航栏按钮之一从 ShellRoute 推送到与 ShellRoute 同一层次结构中的 GoRoute?
目前GoRouter的路由有两个值:ShellRoute和GoRoute。 ShellRoute 中的 Child 代表 Home、Discover 和 Shop Widget。然而,除了上面提到的 Widget 的三个按钮之外,NavBar 还多了一个第四个按钮。这个按钮(MY)用于转到前面提到的 GoRoute。
正如您从下面附加的代码中看到的,我希望在 ShellRoute 上按下第四个按钮时显示登录小部件,因为 GoRoute 堆叠在 ShellRoute 上。但实际上,随着 ShellRoute 被删除,GoRoute 成为顶部堆栈,iOS 没有后退按钮,Android 在 BackPress 时关闭应用程序。
官方文档examples中没有这方面的例子,所以我迷失了很多。
我发现了类似的例子一万个https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/shell_route.dart https://github.com/flutter/packages/blob/main/packages/go_router/example/lib/shell_route.dart在上面的示例中,GoRoute 依赖于 ShellRoute。
我不想要这个。我想让登录路线可以从任何地方访问。
我将在下面附上我的代码和操作屏幕。
我需要你的帮助。
预期成绩:当按下第四个按钮时,GoRoute 会堆叠在 ShellRoute 上,按下背面时 ShellRoute 会重新出现
实际结果:当按下第四个按钮时,ShellRoute 将被删除,创建一个 GoRoute 并将其堆叠在顶部,当您按 Back 时,应用程序将结束。
Performing hot restart...
Syncing files to device iPhone 12...
Restarted application in 368ms.
flutter: MyTest didPush: _PageBasedMaterialPageRoute<void>(MaterialPage<void>("/", [<'280748962'>], {}), animation: AnimationController#0adb5(⏭ 1.000; paused; for _PageBasedMaterialPageRoute<void>(/)))
flutter: MyTest didPush: _PageBasedMaterialPageRoute<void>(MaterialPage<void>("/login", [<'621841910'>], {}), animation: AnimationController#4775c(▶ 0.000; for _PageBasedMaterialPageRoute<void>(/login)))
flutter: MyTest didRemove: _PageBasedMaterialPageRoute<void>(MaterialPage<void>("/shop", [<'280748962'>], {}), animation: AnimationController#0adb5(⏭ 1.000; paused; for _PageBasedMaterialPageRoute<void>(/)))
Code sample
main.dart
void main() {
runApp(const MyApp());
}
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
final _router = GoRouter(
initialLocation: '/',
navigatorKey: _rootNavigatorKey,
observers: [
GoRouterObserver(),
],
routes: [
ShellRoute(
navigatorKey: _shellNavigatorKey,
builder: (context, state, child) {
return ScaffoldWithNavBar(child: child);
},
routes: [
GoRoute(
path: '/',
builder: (context, state) {
return const Home();
},
),
GoRoute(
path: '/discover',
builder: (context, state) {
return const Discover();
},
),
GoRoute(
path: '/shop',
builder: (context, state) {
return const Shop();
}),
],
),
GoRoute(
path: '/login',
builder: (context, state) {
return const Login();
},
),
],
);
class GoRouterObserver extends NavigatorObserver {
@override
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
print('MyTest didPush: $route');
}
@override
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
print('MyTest didPop: $route');
}
@override
void didRemove(Route<dynamic> route, Route<dynamic>? previousRoute) {
print('MyTest didRemove: $route');
}
@override
void didReplace({Route<dynamic>? newRoute, Route<dynamic>? oldRoute}) {
print('MyTest didReplace: $newRoute');
}
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Platform',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routerConfig: _router,
);
}
}
scaffold_with_nav_bar.dart
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class ScaffoldWithNavBar extends StatefulWidget {
const ScaffoldWithNavBar({super.key, required this.child});
final Widget child;
@override
State<ScaffoldWithNavBar> createState() => _ScaffoldWithNavBarState();
}
class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
int _currentIndex = 0;
static const List<MyCustomBottomNavBarItem> tabs = [
MyCustomBottomNavBarItem(
icon: Icon(Icons.home),
activeIcon: Icon(Icons.home),
label: 'HOME',
initialLocation: '/',
),
MyCustomBottomNavBarItem(
icon: Icon(Icons.explore_outlined),
activeIcon: Icon(Icons.explore),
label: 'DISCOVER',
initialLocation: '/discover',
),
MyCustomBottomNavBarItem(
icon: Icon(Icons.storefront_outlined),
activeIcon: Icon(Icons.storefront),
label: 'SHOP',
initialLocation: '/shop',
),
MyCustomBottomNavBarItem(
icon: Icon(Icons.account_circle_outlined),
activeIcon: Icon(Icons.account_circle),
label: 'MY',
initialLocation: '/login',
),
];
@override
Widget build(BuildContext context) {
const labelStyle = TextStyle(fontFamily: 'Roboto');
return Scaffold(
body: SafeArea(child: widget.child),
bottomNavigationBar: BottomNavigationBar(
selectedLabelStyle: labelStyle,
unselectedLabelStyle: labelStyle,
selectedItemColor: const Color(0xFF434343),
selectedFontSize: 12,
unselectedItemColor: const Color(0xFF838383),
showUnselectedLabels: true,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
_goOtherTab(context, index);
},
currentIndex: _currentIndex,
items: tabs,
),
);
}
void _goOtherTab(BuildContext context, int index) {
if (index == _currentIndex) return;
GoRouter router = GoRouter.of(context);
String location = tabs[index].initialLocation;
if (index == 3) {
router.push(location);
}
setState(() {
_currentIndex = index;
router.go(location);
});
}
}
class MyCustomBottomNavBarItem extends BottomNavigationBarItem {
final String initialLocation;
const MyCustomBottomNavBarItem(
{required this.initialLocation,
required Widget icon,
String? label,
Widget? activeIcon})
: super(icon: icon, label: label, activeIcon: activeIcon ?? icon);
}
Logs
info • Avoid `print` calls in production code • lib/main.dart:62:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:67:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:72:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:77:5 • avoid_print
info • Prefer const with constant constructors • lib/sections/discover/discover.dart:11:16 • prefer_const_constructors
info • Avoid using private types in public APIs • lib/sections/exhibition/detail_exhibition.dart:10:3 • library_private_types_in_public_api
info • Prefer const with constant constructors • lib/sections/exhibition/exhibition.dart:11:16 • prefer_const_constructors
info • Unused import: 'package:knowd_platform/sections/discover/discover.dart' • lib/sections/home/home.dart:2:8 • unused_import
info • Prefer const with constant constructors • lib/sections/home/home.dart:21:15 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/login.dart:11:16 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/login_router.dart:8:34 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/singup.dart:11:16 • prefer_const_constructors
info • Avoid using private types in public APIs • lib/sections/main_tab_bar.dart:12:3 • library_private_types_in_public_api
info • Private field could be final • lib/sections/main_tab_bar.dart:17:16 • prefer_final_fields
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:18:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:19:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:20:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:21:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:41:18 • prefer_const_constructors
info • Prefer const literals as parameters of constructors on @immutable classes • lib/sections/main_tab_bar.dart:59:17 • prefer_const_literals_to_create_immutables
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:60:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:61:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:64:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:65:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:68:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:69:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:72:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:73:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/shop.dart:10:16 • prefer_const_constructors
info • Avoid `print` calls in production code • lib/main.dart:62:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:67:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:72:5 • avoid_print
info • Avoid `print` calls in production code • lib/main.dart:77:5 • avoid_print
info • Prefer const with constant constructors • lib/sections/discover/discover.dart:11:16 • prefer_const_constructors
info • Avoid using private types in public APIs • lib/sections/exhibition/detail_exhibition.dart:10:3 • library_private_types_in_public_api
info • Prefer const with constant constructors • lib/sections/exhibition/exhibition.dart:11:16 • prefer_const_constructors
info • Unused import: 'package:knowd_platform/sections/discover/discover.dart' • lib/sections/home/home.dart:2:8 • unused_import
info • Prefer const with constant constructors • lib/sections/home/home.dart:21:15 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/login.dart:11:16 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/login_router.dart:8:34 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/login/singup.dart:11:16 • prefer_const_constructors
info • Avoid using private types in public APIs • lib/sections/main_tab_bar.dart:12:3 • library_private_types_in_public_api
info • Private field could be final • lib/sections/main_tab_bar.dart:17:16 • prefer_final_fields
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:18:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:19:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:20:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:21:5 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:41:18 • prefer_const_constructors
info • Prefer const literals as parameters of constructors on @immutable classes • lib/sections/main_tab_bar.dart:59:17 • prefer_const_literals_to_create_immutables
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:60:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:61:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:64:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:65:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:68:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:69:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:72:13 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/main_tab_bar.dart:73:21 • prefer_const_constructors
info • Prefer const with constant constructors • lib/sections/shop.dart:10:16 • prefer_const_constructors