go_router ShellRoute, how to use the go method to jump routes and process the carried parameters
code:
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final GlobalKey<NavigatorState> _rootNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'root');
final GlobalKey<NavigatorState> _shellNavigatorKey =
GlobalKey<NavigatorState>(debugLabel: 'shell');
void main() {
runApp(ShellRouteExampleApp());
}
class ShellRouteExampleApp extends StatelessWidget {
ShellRouteExampleApp({super.key});
final GoRouter _router = GoRouter(
navigatorKey: _rootNavigatorKey,
initialLocation: '/a',
debugLogDiagnostics: true,
routes: <RouteBase>[
StatefulShellRoute.indexedStack(
builder: (context, state, navigationShell) {
return ScaffoldWithNavBar(
child: navigationShell,
);
},
branches: [
StatefulShellBranch(routes: [
GoRoute(
path: '/a',
name: 'a',
builder: (BuildContext context, GoRouterState state) {
return ScreenA(
login: bool.parse(
state.uri.queryParameters['login'] ?? 'false'),
);
},
),
]),
StatefulShellBranch(routes: [
GoRoute(
path: '/b',
builder: (BuildContext context, GoRouterState state) {
return const ScreenB();
},
),
]),
]),
GoRoute(
path: '/login',
name: 'login',
parentNavigatorKey: _rootNavigatorKey,
builder: (BuildContext context, GoRouterState state) {
return const LoginScreen();
},
),
],
);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
routerConfig: _router,
);
}
}
class ScaffoldWithNavBar extends StatelessWidget {
const ScaffoldWithNavBar({
required this.child,
super.key,
});
/// The widget to display in the body of the Scaffold.
/// In this sample, it is a Navigator.
final Widget child;
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'A Screen',
),
BottomNavigationBarItem(
icon: Icon(Icons.business),
label: 'B Screen',
),
],
currentIndex: _calculateSelectedIndex(context),
onTap: (int idx) => _onItemTapped(idx, context),
),
);
}
static int _calculateSelectedIndex(BuildContext context) {
final String location = GoRouterState.of(context).uri.toString();
if (location.startsWith('/a')) {
return 0;
}
if (location.startsWith('/b')) {
return 1;
}
if (location.startsWith('/c')) {
return 2;
}
return 0;
}
void _onItemTapped(int index, BuildContext context) {
switch (index) {
case 0:
GoRouter.of(context).go('/a');
break;
case 1:
GoRouter.of(context).go('/b');
break;
case 2:
GoRouter.of(context).go('/c');
break;
}
}
}
class ScreenA extends StatefulWidget {
final bool login;
const ScreenA({super.key, required this.login});
@override
State<ScreenA> createState() => _ScreenAState();
}
class _ScreenAState extends State<ScreenA> {
@override
void initState() {
super.initState();
afterLogin();
}
void afterLogin() {
print('login success :${widget.login}');
//todo someting then setState
setState(() {});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text('Screen A login:${widget.login}'),
widget.login == true
? const Text('login success')
: const Text('login fail'),
TextButton(
onPressed: () {
context.push('/login');
},
child: const Text('push login'),
),
],
),
),
);
}
}
/// The second screen in the bottom navigation bar.
class ScreenB extends StatelessWidget {
/// Constructs a [ScreenB] widget.
const ScreenB({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('Screen B'),
TextButton(
onPressed: () {
GoRouter.of(context).go('/b/details');
},
child: const Text('View B details'),
),
],
),
),
);
}
}
/// The third screen in the bottom navigation bar.
class LoginScreen extends StatelessWidget {
/// Constructs a [LoginScreen] widget.
const LoginScreen({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('login'),
TextButton(
onPressed: () {
GoRouter.of(context)
.goNamed('a', queryParameters: {'login': 'true'});
},
child: const Text('login'),
),
],
),
),
);
}
}
I want to click "push login" in "A Screen" to jump to the login page, then click "login" to jump back to "A Screen" on the home page, and call the "afterLogin" method in it, but I can't trigger it using go. In any middle stage of life, push can’t be used to jump. What should I do?
The problem is the method is not called anywhere. Call it by
afterLogin();
under the build method inScreenA
to see the print.It should look like this
Edit
If
ScreenA
is aStatefulWidget
,initState()
is called once when theState
object is instantiated. Pushing toLoginScreen
then using thegoNamed
method, looks like it's goes to the previous instance ofScreenA
.Try one of these methods:
Method 1 instead of pushing from
ScreenA
, dogo
instead. However, this does not provide a previous page to go back to by a back button.Method 2 pushing to the next screen and returning a value by popping.