如何检查当前路线是哪条?

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);
      
    
  

请注意,使用pushNamedpopAndPushNamed 的这种实现要求您在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 中检查当前路线

ROS不做标记Mark时,上网默认走哪条路线?

Angular 2 获取当前路线

如何从 RouteData 获取路线名称?

Laravel 4如何检查一条路线是不是仅来自另一条路线/重定向?

Core Motion:如何判断“向上”是哪条路?