Flutter 移除所有路由

Posted

技术标签:

【中文标题】Flutter 移除所有路由【英文标题】:Flutter remove all routes 【发布时间】:2018-02-03 23:20:47 【问题描述】:

我想开发一个注销按钮,它会将我发送到登录路径并从Navigator 中删除所有其他路径。该文档似乎没有解释如何制作 RoutePredicate 或具有任何类型的 removeAll 功能。

【问题讨论】:

【参考方案1】:

我能够使用以下代码完成此操作:

Navigator.of(context)
    .pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);

这里的秘密是使用一个总是返回 false (Route&lt;dynamic&gt; route) =&gt; false 的 RoutePredicate。在这种情况下,它会删除所有路由,除了我推送的新 /login 路由。

【讨论】:

非常感谢它成功了。能不能发个链接,让我了解更多。。。。 我遇到了这个问题!在 ios 上,通过使用本机视图作为小部件,在使用您的方法后,本机视图无法正确处理并继续存在,因此我有一个视图将永远不会再次在某种背景下运行并且无法处理.这似乎只发生在 iOS 设备上。 @LorenzoImperatrice 您找到解决此问题的方法了吗?我有类似的问题 即使使用了这个,我仍然有打开的实例。还有其他解决方案来推送屏幕并删除堆栈的其余部分吗? 我们如何使用这种方法传递参数。【参考方案2】:

我可以使用以下代码 sn-p :

 Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) =>
    LoginScreen()), (Route<dynamic> route) => false),

如果要删除推送路由下面的所有路由,RoutePredicate总是返回false,例如(Route route) => false .

【讨论】:

如果你想在导航页面上发送参数,那么你可以使用 "Navigator.pushNamedAndRemoveUntil(context, "/newRouteName", (r) => false, arguments: "arg_1": firstArgument, " arg_2": secondArgument );"【参考方案3】:

另一种选择是popUntil()

Navigator.of(context).popUntil(ModalRoute.withName('/root'));

这将弹出所有路线,直到您返回指定路线。

【讨论】:

我更喜欢这个答案!【参考方案4】:

另一种解决方案是使用pushAndRemoveUntil()。要删除所有其他路由,请使用ModalRoute.withName('/')

Navigator.pushAndRemoveUntil(
    context,   
    MaterialPageRoute(builder: (BuildContext context) => Login()), 
    ModalRoute.withName('/')
);

参考:https://api.flutter.dev/flutter/widgets/NavigatorState/pushAndRemoveUntil.html

【讨论】:

【参考方案5】:

如果您想返回特定屏幕并且不使用命名路由器,可以使用下一个方法

例子:

Navigator.pushAndRemoveUntil(context,
                  MaterialPageRoute(builder: (BuildContext context) => SingleShowPage()),
                  (Route<dynamic> route) => route is HomePage
              );

使用 route is HomePage,您可以检查小部件的名称。

【讨论】:

什么是 NoAnimatedRoute?在 Flutter 中找不到具有此类名称的类 @kashlo 不要注意 =) 只是我的实现可以改用 MaterialPageRoute。但我已经编辑了答案,谢谢。 (Route route) => route.isFirst) 如果有人想删除直到第一条路线。【参考方案6】:

如果您使用的是命名路由,您可以简单地做到这一点:

Navigator.pushNamedAndRemoveUntil(context, "/login", (Route<dynamic> route) => false);

其中 "/login" 是您要推送到路由堆栈上的路由。

请注意:

此语句删除堆栈中的所有路由,并将推送的路由作为根。

【讨论】:

【参考方案7】:

我不知道为什么没有人提到使用SchedularBindingInstance 的解决方案,虽然聚会有点晚了,我认为这最初是正确的做法answered here

SchedulerBinding.instance.addPostFrameCallback((_) async 
   Navigator.of(context).pushNamedAndRemoveUntil(
      '/login',
      (Route<dynamic> route) => false);
);

上面的代码删除了所有路由并导航到'/login',这也确保在通过调度回调导航到新路由之前渲染所有帧

【讨论】:

【参考方案8】:

不确定我这样做是否正确

但这适合我弹出直到根小部件的用例

void popUntilRoot(Object result) 
    if (Navigator.of(context).canPop()) 
      pop();
      popUntilRoot();
    

【讨论】:

我喜欢这个答案,以防您不使用命名路由。如此优雅 Object result参数如何使用?这个功能需要吗?【参考方案9】:

在我的情况下,这个解决方案有效:

Navigator.pushNamedAndRemoveUntil(" The Route you want to go to " , (Route route) => false);

【讨论】:

如果你想去登录或注册你可以简单地调用root :::: Navigator.pushNamedAndRemoveUntil("/ " , (Route route) => false);【参考方案10】:

这对我有用。实际上,我正在使用 bloc 但我的问题是登录屏幕块。注销后没有更新。它保存着以前的模型数据。甚至,我输入了错误的条目它要进入主屏幕。

第 1 步:

Navigator.of(context).pushNamedAndRemoveUntil(
        UIData.initialRoute, (Route<dynamic> route) => false);

在哪里, UIData.initialRoute = "/" or "/login"

第 2 步:

正在刷新屏幕。如果您正在使用 Bloc,那么这将非常有帮助。

runApp(MyApp());

在哪里, MyApp() is the root class.

根类(即 MyApp) 代码

class MyApp extends StatelessWidget 

  final materialApp = Provider(
      child: MaterialApp(
          title: UIData.appName,
          theme: ThemeData(accentColor: UIColor().getAppbarColor(),
            fontFamily: UIData.quickFont,
          ),
          debugShowCheckedModeBanner: false,
          //home: SplashScreen(),
          initialRoute: UIData.initialRoute,
          routes: 
            UIData.initialRoute: (context) => SplashScreen(),
            UIData.loginRoute: (context) => LoginScreen(),
            UIData.homeRoute: (context) => HomeScreen(),
          ,
          onUnknownRoute: (RouteSettings rs) => new MaterialPageRoute(
              builder: (context) => new NotFoundPage(
                appTitle: UIData.coming_soon,
                icon: FontAwesomeIcons.solidSmile,
                title: UIData.coming_soon,
                message: "Under Development",
                iconColor: Colors.green,
              )
          )));

  @override
  Widget build(BuildContext context) 
    return materialApp;
  


void main() => runApp(MyApp());

这是我的注销方法,

void logout() async 
    SharedPreferences preferences = await SharedPreferences.getInstance();
    preferences.clear();

    // TODO: we can use UIData.loginRoute instead of UIData.initialRoute
    Navigator.of(context).pushNamedAndRemoveUntil(
        UIData.initialRoute, (Route<dynamic> route) => false);
    //TODO: It's working as refresh the screen
    runApp(MyApp());
  

【讨论】:

【参考方案11】:

首先查看 chrislondon 的答案,然后知道如果您无权访问(上下文),您也可以这样做。

navigatorKey.currentState.pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);  

【讨论】:

【参考方案12】:
to clear route - 

  onTap: () 
                    //todo to clear route -
                    Navigator.of(context).pop();
                    Navigator.push(context, MaterialPageRoute(builder: (context) => UpdateEmployeeUpdateDateActivity(_token),));
                    widget.listener.onEmployeeDateClick(_day,_month, _year);

【讨论】:

【参考方案13】:

就我而言,我有这幅画 第 1 页(主要)-> 第 2 页 -> 第 3 页 -> 第 4 页。

当我不得不去第4页时,第2页和返回的第3页不必出现,但我必须再次转到第1页。此时我转到第 4 页:

Navigator.pushAndRemoveUntil(
              context,
              MaterialPageRoute(
                  builder: (BuildContext context) =>
                      Workout()),
             (Route<dynamic> route) => route.isFirst);

说明是:转到第 4 页(锻炼)并删除所有以前的页面,最多为 1,即(主)。

在您的情况下,可以从任何东西切换到登录,然后:

Navigator.pushAndRemoveUntil(
              context,
              MaterialPageRoute(
                  builder: (BuildContext context) =>
                      Login()),
             (Route<dynamic> route) => false);

也就是去Login,把之前的所有页面都去掉,因为有false。

【讨论】:

以上是关于Flutter 移除所有路由的主要内容,如果未能解决你的问题,请参考以下文章

Flutter路由跳转及参数传递

Flutter学习三 命名路由

移除Flutter右上角的DEBUG标识

移除Flutter右上角的DEBUG标识

如何移除运行 Flutter 的设备?

Flutter:ListView内部的widget值在移除item时不会更新