如何安全地导航到我的颤振应用程序的默认路由(“主页”)?

Posted

技术标签:

【中文标题】如何安全地导航到我的颤振应用程序的默认路由(“主页”)?【英文标题】:How can I safely navigate to the default route ("home page") of my flutter app? 【发布时间】:2021-02-10 05:13:55 【问题描述】:

编辑:最初这篇文章是专门针对使用全局导航器的,但我发现这个案例并不是专门针对使用全局导航器的。相反,它是一个错误,可能因滥用 Navigator API 而发生。

Flutter 1.22.0 • channel beta • https://github.com/flutter/flutter.git
Framework • revision d408d302e2 (4 weeks ago) • 2020-09-29 11:49:17 -0700
Engine • revision 5babba6c4d
Tools • Dart 2.10.0

我遵循了之前 SO 帖子中的建议。这在某种程度上有效: How to navigate without context in flutter app?

但是,我在简单地使用全局导航键时遇到了一些问题。我无法使用路由谓词调用 popUntil 以导航回我的主屏幕,并且因为 I cannot view the Navigator history stack,我无法有效地调试它。

/// constants/keys.dart
    final GlobalKey<NavigatorState> navKey = new GlobalKey<NavigatorState>();


/// constants/routes.dart
    const String HOME = 'home';
    const String SCREEN_A = 'a';
    const String SCREEN_B = 'b';


/// main.dart
class App extends StatelessWidget 
    @override
    Widget build(BuildContext context) 
        return MaterialApp(
            home: Home(),
            navigatorKey: Keys.navKey,
            onGenerateRoute: (routeSettings) 
                switch (routeSettings.name) 
                    case Routes.HOME:
                        return MaterialPageRoute(
                            builder: (context) => Home(),
                            settings: RouteSettings(name: Routes.HOME),
                        );
                    case Routes.SCREEN_A:
                        return MaterialPageRoute(
                            builder: (context) => ScreenA(),
                            settings: RouteSettings(name: Routes.SCREEN_A),
                        );
                    case Routes.SCREEN_B:
                        return MaterialPageRoute(
                            builder: (context) => ScreenB(),
                            settings: RouteSettings(name: Routes.SCREEN_B),
                        );
                    default:
                        return MaterialPageRoute(
                            builder: (context) => Home(),
                            settings: RouteSettings(name: Routes.HOME),
                        );
                
            ,
        );
    

这表明您不能使用页面查看使用 Navigator API 添加的历史记录。

/// Experiment, instrument build of Home, ScreenA, ScreenB with code to view pages:
Navigator nav = Keys.navKey.currentWidget;
print("Location: Home, Number of pages: $nav.pages.length");
for (Page page in nav.pages) 
  print("Page: $page.name, $page.key, $page.toString()");


/// OUTPUT: 
// Home, Number of pages: 0
// ScreenA, Number of pages: 0
// ScreenB, Number of pages: 0

I did not expect pages to display the navigation history

一些Routes不对应Page对象,即那些 使用 Navigator API(推送和好友)添加到历史记录。一种 不对应 Page 对象的路由称为无页 route 并绑定到与 Page 对象相对应的 Route 历史上低于它。

结束切线

我在使用 Navigator 时遇到的主要痛点是我需要从没有构建上下文的方法中进行导航,并且需要全局键来访问诸如 Navigator 之类的小部件。例如,我必须为蓝牙连接失败附加一个监听器,然后从监听器导航回主屏幕。为此,我不得不依赖全局导航键。我也更喜欢访问全局导航键而不是调用 Navigator.of(context)。

但是,由于我无法查看 Navigator 历史堆栈,因此无法轻松调试我的问题。

我可以通过全局导航键使用这些调用向前导航:

Keys.navKey.currentState.pushNamed(Routes.HOME);

我可以使用任何一个:

Keys.navKey.currentState.pushNamedAndRemoveUntil(Routes.HOME, (Route<dynamic> route) => false);

或:

Keys.navKey.currentState.pushReplacementNamed(Routes.HOME);

向后导航。

但我不能简单地弹出内部导航器历史堆栈而不出现黑屏。

/// Black Screen
Keys.navKey.currentState.popUntil(ModalRoute.withName(Routes.HOME));

对我来说,正确的方法似乎是 popUntil,因为它会从堆栈中弹出除所需路由之外的所有内容。为什么在这个例子中不能简单地调用 popUntil 来安全地导航回主屏幕?

【问题讨论】:

【参考方案1】:

我可以使用这个 sn-p 导航回默认路由:

 Keys.navKey.currentState.popUntil(ModalRoute.withName(Navigator.defaultRouteName));

使用调试器,我看到默认路由名称是 '/' 而不是 'home'。使用 navigator 以编程方式导航不会将初始路由作为 home 推送到堆栈上。这是有道理的。我从不调用 Keys.navKey.currentState.push('home')。如果您想使用导航器返回应用程序默认屏幕,请记住这一点,上述方法调用似乎是正确的方法,除非您找到一种方法将导航器堆栈的底部设置为您的回家路线。

【讨论】:

以上是关于如何安全地导航到我的颤振应用程序的默认路由(“主页”)?的主要内容,如果未能解决你的问题,请参考以下文章

如何通过使用 Vue.js 中的路由器概念单击按钮来简单地从一个组件(主页)导航到另一个组件

如何在颤动中将浏览器 URL 更新为非根导航器的路由更改?

双击按钮时如何修复颤振中的多个导航

颤振自动路由 |如何使用 BlocProvider 包装路由?

如何删除默认导航路线动画

如何在颤振抽屉中返回主页/主页