返回翻译好的部分:Back button not showing when using ShellRouter with GoRouter in flutter

huangapple go评论72阅读模式
英文:

Back button not showing when using ShellRouter with GoRouter in flutter

问题

以下是您要翻译的内容:

"我有一个简单的结构

一个名为ShellRoute的路由,初始页面是Home,一个子路由带有/post/:id。我从主页导航到帖子页面使用push,但返回按钮未显示在应用栏上。

另外值得注意的是,如果在Post小部件中,'context.canPop()' 返回 'true',但是在Shell的'didUpdateWidget'方法中,'WidgetGoRouter.of(context).canPop()' 返回 'false',所以我猜测由于某种原因,Shell的上下文与页面的上下文不同,但我的NavigatorState键是相同的_shellNavigator。然而,如果我在Post小部件上热重载,canPop方法开始返回true,但返回按钮不会出现。

我尝试将两个页面Home和Post设置在同一级别,但没有运气(请参阅注释)。我阅读了文档和Stack Overflow上的另一个答案,我认为我遵循了所有步骤。我可能错过了一些明显的东西。

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(),
    );
  }
}"


<details>
<summary>英文:</summary>

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&#39;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


```Dart
final GlobalKey&lt;NavigatorState&gt; _rootNavigator = GlobalKey(debugLabel: &#39;root&#39;);
final GlobalKey&lt;NavigatorState&gt; _shellNavigator =
    GlobalKey(debugLabel: &#39;shell&#39;);

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

  @override
  State&lt;Shell&gt; createState() =&gt; _ShellState();
}

class _ShellState extends State&lt;Shell&gt; {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        automaticallyImplyLeading: true,
        title: const Text(&#39;Title&#39;),
      ),
      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: &#39;/&#39;, routes: [
    ShellRoute(
        navigatorKey: _shellNavigator,
        builder: (context, state, child) =&gt;
            Shell(key: state.pageKey, child: child),
        routes: [
          GoRoute(
              parentNavigatorKey: _shellNavigator,
              path: &#39;/&#39;,
              builder: (context, state) =&gt; Home(
                    key: state.pageKey,
                  ),
              routes: [
                GoRoute(
                  parentNavigatorKey: _shellNavigator,
                  path: &#39;post/:id&#39;,
                  builder: (context, state) =&gt; Post(
                    key: state.pageKey,
                  ),
                )
              ]),
          // GoRoute(
          //   parentNavigatorKey: _shellNavigator,
          //   path: &#39;/post/:id&#39;,
          //   builder: (context, state) =&gt; Post(
          //     key: state.pageKey,
          //   ),
          // )
        ])
  ]);
}

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

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


</details>


# 答案1
**得分**: 3

以下是翻译后的内容:

"在查看文档、示例等之后...我不确定 ShellRoute 是否真的是这样使用的(尽管我对 Flutter 还很陌生,可能我漏掉了一些东西)。
我认为这与 ShellRoute 在子路由之前进行评估有关,而 canPop() 方法要么还不可用,要么返回 false
因此,在无法依赖 canPop() 方法的情况下,我决定跟踪主路径,并在它不是主路径时显示按钮。这符合我的需求,但我认为它不太具有可扩展性,也不适用于其他用例。

如果这有所帮助,我在这里发布这个。

```dart
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;
  }
}
英文:

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(&#39;Title&#39;),
      ),
      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;
  }
}

huangapple
  • 本文由 发表于 2023年2月19日 05:59:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/75496648.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定