【问题标题】:Is there a way to avoid duplicates in the Navigator _history in Flutter?有没有办法避免在 Flutter 的 Navigator _history 中出现重复?
【发布时间】: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。您可以覆盖页面路由以抑制弹出动画,使其看起来类似于您之前的 stackoverflow.com/questions/49874272/…
  • 您可以在调用 pushNamed() 之前移除Route(routeName)。如果页面不存在(在您的情况下可以忽略),它会引发错误。但是,这样一来,您的任何页面都无法利用弹出页面传递的值,因为它们已被释放。
  • @NavaneethP 遗憾的是,我太笨了,无法在典型上下文之外使用 removeRoute 。我们正在使用一个额外的类“ScreenController”来管理路由转换,但我不知道如何获取 removeRoute 所需的第二个参数(Route 类型)。
  • @Chazman 问题是 pop 只删除堆栈的顶部元素,但如果我喜欢 BasketScreen->ProfileScreen->BasketScreen,我想从堆栈中删除旧的 BasketScreen不删除 ProfileScreen 就无法访问,对吗?
  • 你在使用所有命名路由吗?

标签: flutter dart navigator


【解决方案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);

【讨论】:

  • 对于我的项目,我通过制作一个自定义导航器“修复”了这个问题,该导航器每次用户进入主屏幕时都会清空自身(或其堆栈)。由于用户最终会到达那里,所以这不是什么大问题。 ^^'
猜你喜欢
  • 2021-12-15
  • 2020-12-02
  • 2013-04-11
  • 2022-11-16
  • 1970-01-01
  • 2019-09-07
  • 1970-01-01
  • 2012-06-20
  • 1970-01-01
相关资源
最近更新 更多