我不明白为什么有人使用Navigator.pushNamed()
而不是Navigator.push()
的 normal way 命名路由的原因。
如果我们需要导航到应用程序许多部分的同一屏幕, 这可能导致代码重复。在这些情况下,可能会很方便 定义“命名路线”,并将命名路线用于导航
使用简单路由时如何生成重复项,以及如何使用命名路由来消除重复项?
我不明白
有什么区别Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
来自
Navigator.pushNamed(context, '/second');
在重复上下文中。
答案 0 :(得分:8)
Navigator.push()
:// inside widget A:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
// inside widget B:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
// inside widget C:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute()),
);
现在让我们说您需要更改您的App,小部件SecondRoute
需要在其构造函数上接收一个值。现在,您遇到了一个问题,因为在多个位置上有多个相同代码的副本,因此需要确保更新所有这些副本,这可能很乏味且容易出错:
// inside widget A:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title A',
)),
);
// inside widget B:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title B',
)),
)),
);
// inside widget C:
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SecondRoute(
title: 'Title A', // ERROR! Forgot to change the variable after a copy/paste
)),
)),
);
首先,我永远不建议任何人直接直接使用该名称进行导航,而是使用static
变量引用,如果您将来需要更改它,则可以使用这种方式更简单,更安全。别忘了在任何地方更新它,像这样:
class Routes {
static const String second = '/second';
}
另一种方法是在路由本身内部有一个引用,在static const String
内部有一个SecondRoute
,因此我们可以将其用作SecondRoute.routeName
。这是国际海事组织的个人喜好。
然后,您的窗口小部件将使用以下内容进行导航:
// inside widget A:
Navigator.pushNamed(context, Routes.second); // Routes.second is the same as '/second'
// inside widget B:
Navigator.pushNamed(context, Routes.second);
// inside widget C:
Navigator.pushNamed(context, Routes.second);
现在,如果您需要在创建时将参数传递给SecondRoute
,则可以使用MaterialApp
onGenerateRoute
在集中的位置进行操作,例如tutorial explains in more detail。您的代码将更改为:
// inside widget A:
Navigator.pushNamed(context, Routes.second, arguments: 'Title A');
// inside widget B:
Navigator.pushNamed(context, Routes.second, arguments: 'Title B');
// inside widget C:
// You can still make mistakes here, but the chances are smaller.
Navigator.pushNamed(context, Routes.second, arguments: 'Title C');
MaterialApp(
onGenerateRoute: (settings) {
if (settings.name == Routes.second) {
final String title = settings.arguments;
return MaterialPageRoute(
builder: (context) => SecondRoute(title: title),
);
}
},
);
重复代码的数量减少了,但是另一方面,onGenerateRoute
代码随着您创建更多路线而变得更加复杂,因为它们的所有创建都将集中在此,因此恕我直言,这更多地取决于个人喜好然后是一般准则。
答案 1 :(得分:1)
如果使用push()
,则每次需要导航到该屏幕时,都必须导入SecondRoute所在的文件。对于需要在不同屏幕上浏览的大型项目,这是过多的代码重复。
如果使用pushNamed()
,则只需在MaterialApp中定义一次路线。然后,您可以从任何地方导航到任何屏幕,而无需像使用push()
那样重复相同的操作。
选择PushNamed()
而非另一个Intent intent = new Autocomplete.IntentBuilder(
AutocompleteActivityMode.OVERLAY, fields).setCountry("UK")
.setHint("Search Pickup Location").setInitialQuery(pickup.getText().toString())
.build(this);
startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE);
的另一个重要原因是能够使用它构建自己的导航系统。您甚至可以在某些用户导航到屏幕之前,确定路由是否对某些用户可用。
答案 2 :(得分:1)
Push和PushNamed具有相似的效果,Push将切换到您指定的路由,而PushNamed将切换到具有指定路由名称的路由。
“教程”页面中重复的含义是重复代码而不是路由。
例如,您有一条路线,希望检查用户是否登录并显示相应页面
仅使用“推送”: 第1页:
//This is page 1....
RaisedButton(
child: Text('Go to second'),
onPressed: () {
if (user.state = "login") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(),
),
)
}else{
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPageAnonymous(),
),
)
}
}
)
....
在另一个页面Page2中,您将需要重复相同的代码:
//This is page 2....
RaisedButton(
child: Text('Go to second'),
onPressed: () {
if (user.state = "login") {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPage(),
),
)
}else{
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => SecondPageAnonymous(),
),
)
}
}
)
....
使用PushNamed,您只需声明一次即可,基本上可以一次又一次地重复使用它。
在您的onGenerateRoute中:
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) => FirstPage());
case '/second':
if (user.state = "login") {
return MaterialPageRoute(
builder: (_) => SecondPage()
);
}else{
return MaterialPageRoute(
builder: (_) => SecondPageAnonymous()
);
}
default:
return _errorRoute();
}
},
现在在项目的任何页面中,您都可以这样做:
Navigator.of(context).pushNamed('/second')
每次使用时都无需重复登录检查甚至错误处理。显而易见的好处是,通过防止 重复的代码段 ,而不是一次又一次地重复操作,您可以在整个应用程序中保持一致。
现在,但这并不能防止路由重复!在这种情况下,push和pushNamed没有区别!
但是,由于您的路线已被命名,因此您可以轻松地执行popUntil('/')返回到路线的第一个实例,而不必再次创建它或创建PushReplacementNamed。
答案 3 :(得分:1)
这是我初学者的扑朔迷离的想法:
它使代码更简洁::如果不在高级小部件级别上声明路由,则新的屏幕将无处不在,以响应应用程序中发生的一切。当您一起声明路线时,更容易理解导航框架/结构,在更高的窗口小部件处尤其如此,尤其对于其他开发人员而言。当然,这 并不能帮助您准确地了解这些路线的实际导航时间,但这只是一个小小的改进,使我们回到了声明式范式中。声明的路线提供的提示将帮助新开发人员了解您的导航流程。
答案 4 :(得分:0)
使用具有命名路线的导航时,我看到的唯一好处是在MaterialApp中声明了路线,以便开发人员只能使用已分配的路线,即小部件,页面,
如果有人使用其他方法,则会给出错误'onUnknownRoute被调用。'
答案 5 :(得分:0)
为了理解为什么我们应该使用Navigator.pushNamed而不是Navigator.push,让我们先熟悉Navigator方法。您是否对Navigator.popUntil或Navigator.pushAndRemoveUntil感兴趣? 当我们想将堆栈弹出到特定路径时,我们使用Navigator.popUntil。如果查看文档,您会发现将这些方法与pushNamed方法一起使用非常容易。另外,请检查documentation中的所有方法。当我尝试了解颤动的this路由时,对我来说非常有用。 作为缺点,这种方法很难处理参数。您应该创建onGenerateRoute并为每个路由处理参数。