I want to develop a logout button that will send me to the log in route and remove all other routes from the Navigator
. The documentation doesn't seem to explain how to make a RoutePredicate
or have any sort of removeAll function.

- 237,138
- 77
- 654
- 440

- 12,487
- 5
- 26
- 65
16 Answers
I was able to accomplish this with the following code:
Navigator.of(context)
.pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);
The secret here is using a RoutePredicate that always returns false (Route<dynamic> route) => false
. In this situation it removes all of the routes except for the new /login
route I pushed.

- 12,487
- 5
- 26
- 65
-
1Thanks a lot it worked successfully. Could you please send some link, where I can understand more.... – Pawan Feb 03 '19 at 07:00
-
I got a problem with this! On iOS, by using a native view as widget, after use your method the native view does not dispose properly and continue to exist, as a result i have a view that will be never used again running in a sort of background and impossible to dispose. This seems to happen just on iOS devices. – Lorenzo Imperatrice Apr 29 '19 at 15:37
-
1@LorenzoImperatrice Did you found fix for this issue? I'm having similar issue – Mateusz Tylman Sep 12 '19 at 15:26
-
3I still have instances open even after using this. any other solution to push screen and remove rest of the stack? – Manoj MM Nov 28 '19 at 08:47
-
2How can we pass arguments with this approach. – Developine Dec 17 '19 at 13:40
-
1I came here again year later after the first time saw it. Found answer helpful again and tried to upvote it. So sad that I can't upvote it twice! – Vlad Hudnitsky Jun 03 '20 at 21:05
-
3@Developine I know it's quite late, but in case anyone else needs to pass arguments it can be done this way `Navigator.of(context).pushNamedAndRemoveUntil('/login', (Route
route) => false, arguments: { "key": "value"});` – selected Mar 30 '21 at 11:44 -
what happen is return true? `(Route
route) => true` – BIS Tech May 23 '21 at 17:01
I can do that using the following code snippet :
Navigator.of(context).pushAndRemoveUntil(MaterialPageRoute(builder: (context) =>
LoginScreen()), (Route<dynamic> route) => false);
if you want to remove all the route below the pushed route, RoutePredicate always return false, e.g (Route route) => false.

- 3,674
- 3
- 22
- 36

- 2,326
- 1
- 12
- 13
-
2if you want to send params on navigating page then you can use "Navigator.pushNamedAndRemoveUntil(context, "/newRouteName", (r) => false, arguments: { "arg_1": firstArgument, "arg_2": secondArgument });" – Kamlesh May 15 '21 at 08:48
-
Another alternative is popUntil()
Navigator.of(context).popUntil(ModalRoute.withName('/root'));
This will pop all routes off until you are back at the named route.

- 237,138
- 77
- 654
- 440

- 708
- 5
- 11
Another solution is to use pushAndRemoveUntil()
. To remove all other routes use ModalRoute.withName('/')
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (BuildContext context) => Login()),
ModalRoute.withName('/')
);
Reference: https://api.flutter.dev/flutter/widgets/NavigatorState/pushAndRemoveUntil.html

- 66
- 1
- 8

- 361
- 3
- 3
-
This is really worked. for my scenario . I have a startup page. Which contain 2 buttons. one is login and the other is signup . once we go inside each of those buttons . inside there is a another route area which can navigate through each page. So if I dont use above code . it will go inside inside and inside like inception film. to prevent this code helps. Thanks for the answer. Awesome. – Learning Curious Dec 18 '22 at 11:03
In case you want to go back to the particular screen and you don't use named router can use the next approach
Example:
Navigator.pushAndRemoveUntil(context,
MaterialPageRoute(builder: (BuildContext context) => SingleShowPage()),
(Route<dynamic> route) => route is HomePage
);
With route is HomePage you check the name of your widget.

- 654
- 2
- 7
- 20
-
-
@kashlo Don't pay attention =) It just my implementation can use MaterialPageRoute instead. But I've edited the answer, thanks. – Volodymyr Bilovus Mar 31 '20 at 11:43
-
2(Route
route) => route.isFirst) If some wants to remove until first route. – Hussnain Haidar Oct 11 '20 at 10:14
If you are using namedRoutes,
This statement removes all the routes in the stack and makes the pushed one the root.
then you can do this by simply :
Navigator.pushNamedAndRemoveUntil(context, "/login", (Route<dynamic> route) => false);
Where "/login" is the route you want to push on the route stack.

- 361
- 6
- 15
use popUntil like following
Navigator.popUntil(context, (route) => route.isFirst);

- 841
- 10
- 15
I don't know why no one mentioned the solution using SchedularBindingInstance, A little late to the party though, I think this would be the right way to do it originally answered here
SchedulerBinding.instance.addPostFrameCallback((_) async {
Navigator.of(context).pushNamedAndRemoveUntil(
'/login',
(Route<dynamic> route) => false);
});
The above code removes all the routes and naviagtes to '/login' this also make sures that all the frames are rendered before navigating to new route by scheduling a callback

- 1,278
- 14
- 23

- 17,235
- 8
- 110
- 131
In my case I had this painting Page 1 (Main) -> Page 2 -> Page 3 -> Page 4.
When I had to go to Page 4, the Page 2 and Page 3 going back did not have to appear, but I had to go to Page 1 again. At this point going to Page 4 I did:
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
Workout()),
(Route<dynamic> route) => route.isFirst);
The instructions are: go to page 4 (Workout) and remove all previous pages up to 1, that is (Main).
In your case that can be to switch from anything to a Login, then:
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (BuildContext context) =>
Login()),
(Route<dynamic> route) => false);
That is, go to Login and remove all previous pages, because there is a false.

- 10,364
- 3
- 38
- 48
Not sure if I'm doing this right
but this suits my use-case of popping until by root widget
void popUntilRoot({Object result}) {
if (Navigator.of(context).canPop()) {
pop();
popUntilRoot();
}
}

- 79
- 1
- 2
-
1
-
1How is the `Object result` parameter used? Is it required in this function? – SametSahin Aug 25 '21 at 23:11
In my case this solution works:
Navigator.pushNamedAndRemoveUntil(" The Route you want to go to " , (Route route) => false);

- 1,271
- 6
- 18

- 197
- 2
- 4
-
if you want to go to login or register you can simply call the root :::: Navigator.pushNamedAndRemoveUntil("/ " , (Route route) => false); – Mohamed Mansour May 27 '21 at 16:20
This is working for me. Actually, I was working with bloc but my issue was login screen bloc. It was not updating after logout. It was holding the previous model data. Even, I entered the wrong entry It was going to Home Screen.
Step 1:
Navigator.of(context).pushNamedAndRemoveUntil(
UIData.initialRoute, (Route<dynamic> route) => false);
where,
UIData.initialRoute = "/" or "/login"
Step 2:
It's working to refresh the screen. If you are working with Bloc then It will very helpful.
runApp(MyApp());
where,
MyApp() is the root class.
Root class (i.e. MyApp) code
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());
Here is My Logout method,
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());
}

- 587
- 4
- 22
Use this, it worked perfectly for me:
Navigator.pushNamedAndRemoveUntil(
context, '/loginscreen', (Route<dynamic> route) => false);
Make sure you add the last line, parameter, and you're good to go.

- 63
- 1
- 7
First see chrislondon answer, and then know that you can also do this, if you do not have access to the (context).
navigatorKey.currentState.pushNamedAndRemoveUntil('/login', (Route<dynamic> route) => false);

- 1,460
- 11
- 8
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);
}

- 621
- 6
- 16
Newer Flutter version seem to replace
(Route<dynamic> route) => false);
by
ModalRoute.withName('/'));

- 6,394
- 10
- 58
- 131