chrislondon
chrislondon

Reputation: 12031

Flutter remove all routes

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.

Upvotes: 235

Views: 253804

Answers (17)

Muhammad Aamir
Muhammad Aamir

Reputation: 2676

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.

Upvotes: 189

Ologunde Olawale
Ologunde Olawale

Reputation: 61

Using GetX makes it easier.

Get.offAll( ()=> Loginpage() ) //will remove all previous routes and navigate you to login page Get.offNamed('/login_page') //does the same thing.

Upvotes: 0

Bo Kristensen
Bo Kristensen

Reputation: 1650

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

Upvotes: 3

iKK
iKK

Reputation: 7012

Newer Flutter version seem to replace

(Route<dynamic> route) => false);

by

ModalRoute.withName('/'));

Upvotes: 1

Kelvin Mboto
Kelvin Mboto

Reputation: 370

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.

Upvotes: 20

Ephraim
Ephraim

Reputation: 63

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.

Upvotes: 5

Mohamed Kamel
Mohamed Kamel

Reputation: 937

use popUntil like following

Navigator.popUntil(context, (route) => route.isFirst);

Upvotes: 21

AlexPad
AlexPad

Reputation: 10879

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.

Upvotes: 9

Mohamed Mansour
Mohamed Mansour

Reputation: 329

In my case this solution works:

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

Upvotes: 7

Mahesh Jamdade
Mahesh Jamdade

Reputation: 20221

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

Upvotes: 11

Mantawy
Mantawy

Reputation: 381

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

Upvotes: 38

s.j
s.j

Reputation: 641

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

Upvotes: 2

Vinesh Raju
Vinesh Raju

Reputation: 79

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

Upvotes: 7

rockstar
rockstar

Reputation: 687

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

Upvotes: 6

Volodymyr Bilovus
Volodymyr Bilovus

Reputation: 761

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.

Upvotes: 26

nleslie
nleslie

Reputation: 774

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.

Upvotes: 55

chrislondon
chrislondon

Reputation: 12031

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.

Upvotes: 498

Related Questions