3

I have a simple structure

A ShellRoute with Home as a initial page a sub route with /post/:id I navigator from the homepage to the post page using push but the backbutton is not showing on the app bar.

Also it's worth noting if on the Post widget the context.canPop() returns true but in the didUpdateWidget Methods of the Shell WidgetGoRouter.of(context).canPop() returns false so my guess is that for some reason the context of the shell is not the same as the one of the page but my NavigatorState keys are the ones of the same _shellNavigator. Yet if I hot reload on the Post Widget the canPop method start returning true but the back button does not appear

I tried setting the two pages Home and Post at the same level with no luck (see comments). I read the doc and another answer on SO and I think I follow everything done. I might be missing something obvious.

go_router: ^6.0.9 
flutter: 3.3.0
final GlobalKey<NavigatorState> _rootNavigator = GlobalKey(debugLabel: 'root');
final GlobalKey<NavigatorState> _shellNavigator =
    GlobalKey(debugLabel: 'shell');

class Shell extends StatefulWidget {
  const Shell({super.key, required this.child});
  final Widget child;

  @override
  State<Shell> createState() => _ShellState();
}

class _ShellState extends State<Shell> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: true,
        title: const Text('Title'),
      ),
      body: widget.child,
    );
  }
}

class App extends StatelessWidget {
  App({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp.router(
      routerDelegate: _router.routerDelegate,
      routeInformationParser: _router.routeInformationParser,
      routeInformationProvider: _router.routeInformationProvider,
    );
  }

  final GoRouter _router =
      GoRouter(navigatorKey: _rootNavigator, initialLocation: '/', routes: [
    ShellRoute(
        navigatorKey: _shellNavigator,
        builder: (context, state, child) =>
            Shell(key: state.pageKey, child: child),
        routes: [
          GoRoute(
              parentNavigatorKey: _shellNavigator,
              path: '/',
              builder: (context, state) => Home(
                    key: state.pageKey,
                  ),
              routes: [
                GoRoute(
                  parentNavigatorKey: _shellNavigator,
                  path: 'post/:id',
                  builder: (context, state) => Post(
                    key: state.pageKey,
                  ),
                )
              ]),
          // GoRoute(
          //   parentNavigatorKey: _shellNavigator,
          //   path: '/post/:id',
          //   builder: (context, state) => Post(
          //     key: state.pageKey,
          //   ),
          // )
        ])
  ]);
}

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

  @override
  Widget build(BuildContext context) {
    var data = [
      {'id': 'Route a'},
      {'id': 'Route b'},
    ];
    return GridView.count(
      crossAxisSpacing: 5,
      mainAxisSpacing: 5,
      crossAxisCount: 2,
      children: data
          .map((e) => Center(
                child: InkWell(
                  onTap: () {
                    GoRouter.of(context).push("/post/${e['id']}");
                    // context.push("/post/${e['id']}");
                  },
                  child: Text(e['id']!,
                      style: const TextStyle(
                        color: Colors.black,
                      )),
                ),
              ))
          .toList(),
    );
  }
}
MorganT
  • 155
  • 1
  • 10

1 Answers1

2

After digging into the doc, examples etc... I'm not sure ShellRoute is really intended that way (yet I'm quite new to flutter I might have missed something) I think it's related to the fact that the ShellRoute is evaluated before the child route and the canPop() method is either not available yet or return false. So without being able to rely on the canPop() method I just decided to keep track of the home path and display the button if it's not the home path. It fits my need but I don't think it's really scalable or fits other use cases.

Yet if it can help I post this here.

class Shell extends StatelessWidget {
  const Shell({super.key, required this.child});
  final Widget child;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: _showLeading(context) ? _leadButton(context) : null,
        title: const Text('Title'),
      ),
      body: child,
    );
  }

  Widget _leadButton(BuildContext context) {
    return GestureDetector(
      onTap: () {
        context.pop();
      },
      child: const Icon(Icons.arrow_back),
    );
  }

  bool _showLeading(BuildContext context) {
    return GoRouter.of(context).location != homeRoutePath;
  }
}
MorganT
  • 155
  • 1
  • 10