有没有办法避免在 Flutter 的 Navigator _history 中出现重复?

Posted

技术标签:

【中文标题】有没有办法避免在 Flutter 的 Navigator _history 中出现重复?【英文标题】:Is there a way to avoid duplicates in the Navigator _history in Flutter? 【发布时间】:2020-11-20 06:45:35 【问题描述】:

所以我有一个应用程序,比如说,它只包含一个主屏幕、一个配置文件屏幕和一个购物篮屏幕。从主/主屏幕,我可以访问其他两个屏幕。实际上,我可以通过侧边栏访问所有这三个屏幕。 如果我在调试模式下启动应用程序,我可以如下导航:

HomeScreen -> ProfileScreen -> HomeScreen (over sidebar) -> Profile Screen.

所有这些都是通过 Navigator.pushNamed() 完成的。这意味着,导航器的 _history 堆栈具有:

主屏幕 个人资料屏幕 主屏幕 个人资料屏幕

这有点愚蠢,它使用 RAM 而无需这样做。 我可以通过每次进入 HomeScreen 时使用 popUntil() 来解决这个问题,这样我就有了一个新的历史记录,但如果我这样做就无济于事了:

HomeScreen -> ProfileScreen -> BasketScreen (over sidebar) -> Profile Screen (over sidebar) -> BasketScreen (over sidebar).

如何从历史记录中删除 RIGHT 屏幕,最好不要制作自己的导航器?有可能吗?我的意思是,理想情况下,Navigator 在最后一个示例之后的历史应该是这样的:

主屏幕 个人资料屏幕 篮子屏幕

(意思是如果调用了 BasketScreen,它会从历史记录中删除所有先前的 BasketScreen,等等)

还是一开始就允许这样的循环调用只是我的错误?虽然我怀疑我是唯一一个这样使用侧边栏的人。

【问题讨论】:

我想如果您担心它,您可以在推送之前查看 pop。您可以覆盖页面路由以抑制弹出动画,使其看起来类似于您之前的 ***.com/questions/49874272/… 您可以在调用 pushNamed() 之前移除Route(routeName)。如果页面不存在(在您的情况下可以忽略),它会引发错误。但是,这样一来,您的任何页面都无法利用弹出页面传递的值,因为它们已被释放。 @NavaneethP 遗憾的是,我太笨了,无法在典型上下文之外使用 removeRoute 。我们正在使用一个额外的类“ScreenController”来管理路由转换,但我不知道如何获取 removeRoute 所需的第二个参数(Route 类型)。 @Chazman 问题是 pop 只删除堆栈的顶部元素,但如果我喜欢 BasketScreen->ProfileScreen->BasketScreen,我想从堆栈中删除旧的 BasketScreen不删除 ProfileScreen 就无法访问,对吗? 你在使用所有命名路由吗? 【参考方案1】:

我最近遇到了同样的问题,此外我有可能稍后需要删除路线。要解决重复页面的问题,只需使用

Navigator.pushReplacementNamed(context, name)

而不是

Navigator.pushNamed(context, name)

如果您需要更多的路由控制和上下文,唯一真正的方法是创建一个自定义 NavigatorObserver,将其添加到您的 MaterialApp,然后在需要删除页面时引用它(就像您尝试在没有实际出现在 Navigator 历史记录中的情况下删除路线,它会抛出错误)。这个 NavigatorObserver 应该适用于大多数用途。

需要注意的一点是,您似乎无法删除 NavigatorObserver 内的路由,因为它似乎在进行更改时将自己锁定为更改。

class Observatory extends NavigatorObserver

  List<Route> routeHistory = List();

  @override
  void didPush(Route route, Route previousRoute) 
    routeHistory.add(route);
    super.didPush(route, previousRoute);
  

  @override
  void didPop(Route route, Route previousRoute) 
    routeHistory.removeLast();
    super.didPop(route, previousRoute);
  

  @override
  void didRemove(Route route, Route previousRoute) 
    var beginIndex = routeHistory.indexOf(route);
    var endIndex = routeHistory.indexOf(previousRoute);
    if((endIndex == -1 && beginIndex != -1) || beginIndex -1 == endIndex)
      routeHistory.remove(route);
    else if(endIndex != -1 && beginIndex != -1)
      routeHistory.removeRange(beginIndex,endIndex);
    super.didRemove(route, previousRoute);
  

  @override
  void didReplace(Route newRoute, Route oldRoute) 
    if(routeHistory.contains(oldRoute))
      routeHistory[routeHistory.indexOf(oldRoute)] = newRoute;
    super.didReplace(newRoute: newRoute, oldRoute: oldRoute);
  

  bool containsRoute(Route route) => routeHistory.contains(route);

现在每当我需要删除路线时,我都会这样做

if(observatory.containsRoute(route))
    Navigator.remove(context, route);

【讨论】:

对于我的项目,我通过制作一个自定义导航器“修复”了这个问题,该导航器每次用户进入主屏幕时都会清空自身(或其堆栈)。由于用户最终会到达那里,所以这不是什么大问题。 ^^'

以上是关于有没有办法避免在 Flutter 的 Navigator _history 中出现重复?的主要内容,如果未能解决你的问题,请参考以下文章

如何避免在codemagic中从git触发构建

Flutter 中的 pushReplacementNamed 和 popAndPushNamed 有啥区别?

Flutter:有没有办法检查小部件是不是已构建[重复]

有没有办法在 Flutter 的 TabBar 中创建下拉列表?

有没有办法在 Flutter 上为 firestore 数据库生成模型类?

有没有办法实现 Flutter ***小吃店?