如何检查当前路线是哪条?
Posted
技术标签:
【中文标题】如何检查当前路线是哪条?【英文标题】:How to check which the current Route is? 【发布时间】:2018-11-21 20:19:06 【问题描述】:我想使用抽屉导航到不同的路线,但如果我已经在该路线上,我不想每次点击它时都打开一个新的路线实例,而是我更喜欢在这种情况下新路线未开通。到目前为止,这是我的代码:
Widget build(BuildContext context)
return new Drawer(
child:
new ListView(
children: <Widget>[
new ListTile(
title: new Text("NewRoute"),
onTap: ()
Navigator.of(context).pop;
Navigator.of(context).pushNamed('/NewRoute');
)
)
)
我想使用条件语句来检查我们是否在某个路线上。我知道有一种方法可以使用 Route 类的 isCurrent 来检查我们当前所在的 Route
https://docs.flutter.io/flutter/widgets/Route/isCurrent.html
虽然我不确定如何实现它。
提前谢谢你!
【问题讨论】:
使用docs.flutter.io/flutter/widgets/RouteObserver-class.html 保留最后一个事件并将其提供给相关方可能会起作用(我自己没有尝试过)。 有趣的是,RouteAware
方法不提供路由设置。所以RouteAware
你无法知道当前路由的名称是什么。
How to get current route path in Flutter?的可能重复
【参考方案1】:
Navigator
不会暴露当前路由。
您可以改为使用Navigator.popUntil(callback)
作为popUtil
将当前Route
传递给回调,其中包括它的名称和内容。
final newRouteName = "/NewRoute";
bool isNewRouteSameAsCurrent = false;
Navigator.popUntil(context, (route)
if (route.settings.name == newRouteName)
isNewRouteSameAsCurrent = true;
return true;
);
if (!isNewRouteSameAsCurrent)
Navigator.pushNamed(context, newRouteName);
【讨论】:
有趣的是,当我尝试你的解决方案时(我会说非常聪明)我收到:断言失败:布尔表达式不能为空,虽然我确实通过绕过 Navigotor 对布尔值的使用让它工作.pushNamed(context, NewRouteName);在第一个 if 语句中,同时将条件更改为 !=. 您是否忘记将isNewRouteSameAsCurrent
初始化为false?
我初始化了它,但有趣的是,即使没有当前的布尔值开始,它仍然会抛出相同的异常 xD
你解决了空布尔异常吗?我遇到了同样的问题
此代码是否适用于主要路线? route.settings.name 只返回 /
。【参考方案2】:
这应该会给你确切的路线名称
import 'package:path/path.dart';
ModalRoute.of(context).settings.name
为避免出现空异常,请执行此操作
var route = ModalRoute.of(context);
if(route!=null)
print(route.settings.name);
【讨论】:
避免空指针异常的更好方法:ModalRoute.of(context)?.settings?.name
ModalRoute.of(context).settings.name 在版本 1.17.0 releasebuild 中将我作为小部件返回。但它在调试构建时工作正常。有什么想法吗?
由于某种原因,Rémi Rousselet 的方法对我有用,但这个总是无效。【参考方案3】:
这是 Dart 扩展方法的完美用例(基于 Rémi Rousselet 的回答):
extension NavigatorStateExtension on NavigatorState
void pushNamedIfNotCurrent( String routeName, Object arguments )
if (!isCurrent(routeName))
pushNamed( routeName, arguments: arguments );
bool isCurrent( String routeName )
bool isCurrent = false;
popUntil( (route)
if (route.settings.name == routeName)
isCurrent = true;
return true;
);
return isCurrent;
然后它看起来像这样干净:
Navigator.of(context).pushNamedIfNotCurrent('/NewRoute');
【讨论】:
lates flutter 1.20.2 throws error ambiguous_extension_member_access 你应该在 NavigatorState 上为 ex extension MyNavigatorStateExtension 使用不同的扩展名,并以 MyNavigatorStateExtension.of(context) 的方式使用它。 pushNamedIfNotCurrent route.settings.name 始终为空【参考方案4】:你可以只用一个:
Get.currentRoute
使用此包:https://pub.dev/packages/get
你会得到当前的路线。
但是您不需要这样做,因为与标准 Flutter 不同,Get 可以防止用户意外单击按钮两次(如果用户使用的是低成本设备,则会在卡顿后发生)。
那么你只需要使用:Get.to(Home());
就可以了!
出于这个原因,目前,Getx 对于使用 Flutter 的项目实际上是必不可少的。 我查看了所有问题,它们很酷,但它们通常涉及使用 popUntil 来获得对路线的访问权,当其他开发人员阅读您的代码时,这似乎是一种 hack。 使用 GetX,您将不会遇到这种双击问题,因为如果您使用 Get.to(Page(), preventDuplicates: false); 明确禁用它,它只会导航到相同的另一个页面; 请记住,这是一个例外,在您的情况下,您可以简单地使用: Get.to(Page());并导航到下一页而不会有任何重复路线的风险,因为防止这种事情已经成为标准。
获取当前路线似乎也涉及很多样板文件,使用 Get 可以获得当前路线的名称(即使您没有命名路线,它也会给您它的名称),使用简单的:Get.currenteRoute
。
好吧,现在回答这个问题有点晚了,但我希望你和其他阅读这篇文章的用户喜欢
【讨论】:
如何使用 GetX 包监听路由变化?谢谢 请附上disclosure about your connection to the project。【参考方案5】:Rémi's answer 确实帮助了我,但如果你像我一样是 Flutter/Dart 的新手,需要一段时间才能理解。所以这是我的版本,带有一些额外的检查和解释性文档:
/// Navigates through the application. Only replaces the top Route if it is
/// different from the new Route. Always keeps the home page as base of the
/// Navigator stack. New screens are pushed on the Navigator stack. When the
/// user switches between non-home screens, the new screen replaces the old
/// screen. In this way, the stack of screens from the drawer is never higher
/// than 2. Returning to the HomeScreen is done by just popping the current
/// Route.
void _changeRoute(BuildContext context, String newRouteName)
// Close drawer
Navigator.pop(context);
// Check current screen status
bool currentRouteIsHome = false;
bool currentRouteIsNewRoute = false;
Navigator.popUntil(context, (currentRoute)
// This is just a way to access currentRoute; the top route in the
// Navigator stack.
if (currentRoute.settings.name == HomeScreen.ROUTE_NAME)
currentRouteIsHome = true;
if (currentRoute.settings.name == newRouteName)
currentRouteIsNewRoute = true;
// Return true so popUntil() pops nothing.
return true;
);
// Switch screen
if (!currentRouteIsNewRoute)
// Only switch screen if new route is different from current route.
if (currentRouteIsHome)
// Navigate from home to non-home screen.
Navigator.pushNamed(context, newRouteName);
else
if (newRouteName == HomeScreen.ROUTE_NAME)
// Navigate from non-home screen to home.
Navigator.pop(context);
else
// Navigate from non-home screen to non-home screen.
Navigator.popAndPushNamed(context, newRouteName);
请注意,使用pushNamed
和popAndPushNamed
的这种实现要求您在routes:
参数的***MaterialApp
中定义Route
名称,如下所示:
new MaterialApp(
routes: <String, WidgetBuilder>
// define the routes
YOUR_SCREEN_ROUTE_NAME: (BuildContext context) => new YourScreen(),
,
)
【讨论】:
如果用户点击返回按钮怎么调用? @TimSim 使用WillPopScope
小部件来注册后退按钮按下。
在移动应用中切换页面看起来有点疯狂...
@Kirill 好吧,您也可以选择使用单个 Scaffol 并根据 Drawer 的状态更新其主体,但代码是如果您想将内置 Routes 与 Drawer 结合使用
currentRoute.settings.name 始终为空【参考方案6】:
ModalRoute.of(context).settings.name
是一个很好的解决这个问题的API,但是这不能在initState()中使用;
【讨论】:
这是评论,不是回答。请多写点,不然很快就关了。 你可以在 @override void didChangeDependencies() 中使用它【参考方案7】:这是我的解决方案。基于 Rémi Rousselet 解决方案。 唯一的区别是防止弹出剩余的“最后”路线。
bool routeFound = false;
String routeName = "/myRoute";
//remove all the routes and stops if find the routeName or if is the last one
Navigator.popUntil(context, (route)
if (route.settings.name == routeName)
expenseRouteFound = true;
//print("route " + routeName + " founded in stack: " + routeFound.toString());
//print("last remaining route into the stack: " + route.isFirst.toString());
return routeFound || route.isFirst;
);
//print("route " + routeName + " founded in stack: " + routeFound.toString());
if (!routeFound)
//print("time to push the route: " + routeName + "!");
Navigator.of(context).pushNamedAndRemoveUntil(routeName, (_)=>false);
【讨论】:
【参考方案8】:基于 Rémi Rousselet 的回答。
String? currentPath;
navigatorKey.currentState?.popUntil((route)
currentPath = route.settings.name;
return true;
);
【讨论】:
【参考方案9】:我正在使用此代码。
*Route route = MaterialPageRoute(builder: (context) => Myinternet());
print(route.isCurrent);
if(route.isCurrent)
*
输出:
显示总是false当前页面未找到
【讨论】:
【参考方案10】:这是我的解决方案。
void redirect(screen)
Navigator.popUntil(context, (route)
if ( route.settings.name != screen)
Navigator.pushNamed(context, screen);
return true;
);
【讨论】:
route.settings.name 始终为空【参考方案11】:使用以下代码检查路由是否位于最顶层...
Route route = MaterialPageRoute(builder: (context) => WidgetName());
if(route.isCurrent)
【讨论】:
小部件无权访问路由。你不能那样做。【参考方案12】:对我来说,我使用的是最懒惰的最简单的方法,因为这里没有答案帮助我在主路由中,我只是使用抽屉类并将当前路由的名称传递给抽屉构造函数,如下所示:
class MyDrawer extends StatelessWidget
final String currentRoute;
MyDrawer(this.currentRoute);
@override
Widget build(BuildContext context)
return Drawer(
child: ListView(
children: <Widget>[
InkWell(
child: Text('secondRoute'),
onTap: ()
if (currentRoute != 'secondRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => secondRoute()));
),
InkWell(
child: Text('thirdRoute'),
onTap: ()
if (currentRoute != 'thirdRoute')
Navigator.push(context,
MaterialPageRoute(builder: (context) => thirdRoute()));
),
在我调用 MyDrawer 类的路由中,我传递当前路由的名称
drawer: MyDrawer('secondRoute'),
【讨论】:
以上是关于如何检查当前路线是哪条?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Iron Router Meteor 中检查当前路线