Flutter:在不提供导航回先前屏幕的情况下切换到新屏幕

123

我正在我的Flutter应用程序中实现身份验证流程。

在登录尝试后,CheckAuth被打开 (检查用户是否已登录,然后相应地打开主屏幕或注册屏幕),使用以下代码:

  void _signIn() async {
    await _auth
        .signInWithEmailAndPassword(
            email: _userEmail.trim(), password: _userPassword.trim())
        .then((task) {
      // go to home screen
      if (task.getIdToken() != null) {
        setState(() {
          Navigator.pushReplacement(
              context,
              new MaterialPageRoute(
                  builder: (BuildContext context) => new CheckAuth()));
        });
      } else {
        print("Authentication failed");
      }
    });
  }

问题:我可以成功登录应用程序,但是如果在登录后点击返回按钮,则会回到登录屏幕(而我希望它退出应用程序)。

问题:如何在Flutter中从一个屏幕移动到另一个屏幕而不返回?

我需要删除导航历史记录吗?还是根本不使用导航?我尝试了Navigator.replace方法,但似乎没有起作用。


1
你的应用程序默认路由是登录界面吗? - Günter Zöchbauer
3
Navigator.pushReplacement() 在我的测试中运行得非常完美。您能否分享完整的代码? - Dhrumil Shah - dhuma1981
@GünterZöchbauer 不是默认路由CheckAuth。问题在于我有一个注册屏幕,我有一个按钮,它通过Navigator.push推送登录屏幕。因此,当用户登录并导航回来时,他回到了注册屏幕。我用Navigator.pushReplacement替换了Navigator.push,现在它运行良好。谢谢! - Darkhan
@dhuma1981 是的,你说得对,.pushReplacement() 很好用。问题是我有一个注册页面,在那里我有一个按钮,它使用 Navigator.push 推送登录页面。所以当用户登录并导航回来时,他会回到注册页面。我用 Navigator.pushReplacement 替换了 Navigator.push,现在它很好用。谢谢! - Darkhan
1
Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => HomeScreen(), ), ); Navigator.pushReplacement() 不起作用。在从当前屏幕重定向到HomeScreen后,仍然显示返回箭头图标。还有其他解决方案吗?请分享。 - Kamlesh
12个回答

202

在离开认证屏幕时,您需要使用Navigator.pushReplacement。不仅仅是重定向到登录页面时才需要使用。


50
使用 Navigator.pushReplacementNamed(context, '/route') 来进行路由导航。该方法用于进行命名路由的跳转,并替换当前路由,让新路由成为栈顶路由。 - Aderbal Nunes
谢谢。在安卓系统中,当我们点击底部的返回按钮时,按钮页面没有返回到主页。 - Vignesh PV
1
在我的情况下不起作用,Dashboard屏幕上显示返回箭头。我在登录屏幕上使用了这段代码:Navigator.of(context).poppushReplacementNamed(DashboardScreen.routeName); - Kamlesh
2
Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => HomeScreen(), ), ); Navigator.pushReplacement() 不起作用。在从当前屏幕重定向到HomeScreen后,仍然显示返回箭头图标。还有其他解决方案吗?请分享。 - Kamlesh
2
Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => HomeScreen()), (Route<dynamic> route) => false, ); 对我很有效。 - Kamlesh
显示剩余2条评论

106

你可以使用pushAndRemoveUntil方法:

将给定的路由推送到最紧密地包围给定上下文的导航器中,然后删除所有先前的路由,直到谓词返回true。 要删除推送路线下面的所有路线,请使用始终返回false的[RoutePredicate](例如(Route<dynamic> route) => false)。

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

1
因为某些奇怪的原因,在 SplashScreen 中使用 Navigator.of(context).pushReplacementNamed 并不起作用(即在目标屏幕的 AppBar 中导航返回按钮不可用),但完全相同的调用在不同的屏幕上却可以工作。你提供的解决方案在这两种情况下都有效,真奇怪,感谢! - egorikem
5
这个答案比其他答案更好,因为即使你在堆栈中有多条路线,你仍然没有返回按钮。 - Philip
1
谢谢,我遇到了同样的问题,你的回答帮助我解决了它。非常感谢。 - Sana'a Al-ahdal

19

你需要使用

Navigator
    .of(_context)
    .pushReplacement(new MaterialPageRoute(builder: (BuildContext context) => page));

_contextBuildContext 对象,page 是你要导航到的页面。


2
每当我按返回按钮(辅助触控的)时,这个程序出现问题,路由会回到上一页。 - Bawantha

6

只需简单地添加以下代码:

Navigator.of(context).pushNamedAndRemoveUntil('/routeName', (route) => false);

5
我已经解决了这个问题,通过弹出当前页面并显示新页面:
Navigator.pop(context);
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (context) => newPage));

5

以下是解决方案 -

使用 pushAndRemoveUntil 替代 pushReplacement

同时,可以使用 maintainState: true

设置根页面

Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(
      builder: (context) => pageName, maintainState: true),
      (Route<dynamic> route) => false);

推送页面到另一个页面

Navigator.push(
context,
MaterialPageRoute(
    builder: (context) => pageName,
    maintainState: false),)

如果你希望页面每次显示时都进行刷新,则使用以下设置:

maintainState: false


该设置可以使页面在每次显示时都进行重新加载,以保证信息的最新性。

5

我想您可能已经解决了这个问题。但是您可以在导航到的 Scaffold 的 AppBar 中设置 "automaticallyLeadingImplied: false"。


3

我们可以使用路由来实现同样的功能,例如:

routes: {

        LoginScreen.route_name: (_) => LoginScreen(),
        .....
      },  

每当你想要推送和移除后退栈时,请使用以下代码:

Navigator.of(context).pushReplacementNamed(LoginScreen.route_name);

注意:在小部件LoginScreen中定义静态字符串


2

如果有人想知道,现在需要返回false的一个新参数 Navigator.of(context).pushNamedAndRemoveUntil('/', (route) => false);


0
Navigator.of(context, rootNavigator: true).pop();
Navigator.pushNamed(context, '/');

请参见“完全基于代码的答案解释”。虽然这可能在技术上是正确的,但它并没有解释为什么它可以解决问题或应该被选为答案。我们应该在帮助解决问题的同时进行教育。 - the Tin Man

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接