【问题标题】: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

虽然我不确定如何实现它。

提前谢谢你!

【问题讨论】:

标签: dart 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

好吧,现在回答这个问题有点晚了,但我希望你和其他阅读这篇文章的用户喜欢

【讨论】:

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

        【讨论】:

          猜你喜欢
          • 2015-08-24
          • 2012-07-09
          • 1970-01-01
          • 2020-03-06
          • 1970-01-01
          • 2011-04-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多