Flattern entferne alle Routen

98

Ich möchte eine Abmeldeschaltfläche entwickeln, die mich zur Anmelderoute sendet und alle anderen Routen aus der entfernt Navigator. Die Dokumentation scheint nicht zu erklären, wie man eine RoutePredicateFunktion removeAll erstellt oder hat.

chrislondon
quelle

Antworten:

267

Dies konnte ich mit folgendem Code erreichen:

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

Das Geheimnis hier ist die Verwendung eines RoutePredicate, das immer false zurückgibt (Route<dynamic> route) => false. In dieser Situation werden alle Routen mit Ausnahme der neuen /loginRoute entfernt, die ich gedrückt habe.

chrislondon
quelle
1
Vielen Dank, es hat erfolgreich funktioniert. Könnten Sie bitte einen Link senden, wo ich mehr verstehen kann ....
Pawan
Ich habe ein Problem damit! Unter iOS, wenn Sie eine native Ansicht als Widget verwenden, wird die native Ansicht nach Verwendung Ihrer Methode nicht ordnungsgemäß entsorgt und bleibt bestehen. Daher habe ich eine Ansicht, die nie wieder verwendet wird und in einer Art Hintergrund ausgeführt wird und nicht mehr verfügbar ist . Dies scheint nur auf iOS-Geräten zu passieren.
Lorenzo Imperatrice
@LorenzoImperatrice Haben Sie eine Lösung für dieses Problem gefunden? Ich habe ein ähnliches Problem
Mateusz Tylman
3
Ich habe immer noch Instanzen geöffnet, auch nachdem ich diese verwendet habe. Gibt es eine andere Lösung, um den Bildschirm zu verschieben und den Rest des Stapels zu entfernen?
Manoj MM
Wie können wir mit diesem Ansatz Argumente übergeben?
Entwickeln Sie
78

Ich kann mit dem folgenden Code-Snippet fertig sein:

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

Wenn Sie die gesamte Route unterhalb der Push- Route entfernen möchten, gibt RoutePredicate immer false zurück , z. B. (Route route) => false .

Amir Khan
quelle
24

Eine andere Alternative ist popUntil()

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

Dadurch werden alle Routen entfernt, bis Sie wieder an der angegebenen Route sind.

nleslie
quelle
1
Ich bevorzuge diese Antwort!
November
14

Eine andere Lösung ist zu verwenden pushAndRemoveUnit(). Um alle anderen Routen zu entfernen, verwenden SieModalRoute.withName('/')

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

Referenz: https://api.flutter.dev/flutter/widgets/NavigatorState/pushAndRemoveUntil.html

Mantawy
quelle
10

Wenn Sie zum jeweiligen Bildschirm zurückkehren möchten und keinen benannten Router verwenden, können Sie den nächsten Ansatz verwenden

Beispiel:

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

Mit route is HomePage überprüfen Sie den Namen Ihres Widgets.

Volodymyr Bilovus
quelle
Was ist NoAnimatedRoute? Ich kann keine Klasse mit einem solchen Namen in Flutter
Kashlo finden.
@kashlo Pass nicht auf =) Nur meine Implementierung kann stattdessen MaterialPageRoute verwenden. Aber ich habe die Antwort bearbeitet, danke.
Volodymyr Bilovus
(Route <dynamic> route) => route.isFirst) Wenn einige bis zur ersten Route entfernen möchten.
Hussnain Haidar
4

Wenn Sie namedRoutes verwenden, können Sie dies einfach tun:

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

Wobei "/ login" die Route ist, die Sie auf den Routenstapel verschieben möchten.

Beachten Sie, dass :

Diese Anweisung entfernt alle Routen im Stapel und macht die Push-Route zur Wurzel.

Kelvin Mboto
quelle
3

Ich weiß nicht, warum niemand die Lösung mit SchedularBindingInstance erwähnt hat. Ein bisschen zu spät zur Party. Ich denke, dies wäre der richtige Weg, dies zu tun. Ursprünglich hier beantwortet

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

Der obige Code entfernt alle Routen und Naviagtes zu '/ login'. Dies stellt auch sicher, dass alle Frames gerendert werden, bevor Sie durch Planen eines Rückrufs zu einer neuen Route navigieren

maheshmnj
quelle
1

Das funktioniert bei mir. Eigentlich habe ich mit Block gearbeitet, aber mein Problem war der Block des Anmeldebildschirms. Es wurde nach dem Abmelden nicht aktualisiert. Es enthielt die vorherigen Modelldaten. Sogar ich habe den falschen Eintrag eingegeben. Es ging zum Startbildschirm.

Schritt 1:

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

wo, UIData.initialRoute = "/" or "/login"

Schritt 2:

Es funktioniert, um den Bildschirm zu aktualisieren. Wenn Sie mit Bloc arbeiten, ist dies sehr hilfreich.

runApp(MyApp());

wo, MyApp() is the root class.

Code der Stammklasse (dh 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());

Hier ist meine Abmeldemethode :

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

Ich bin mir nicht sicher, ob ich das richtig mache

Dies passt jedoch zu meinem Anwendungsfall, bis zum Root-Widget zu poppen

void popUntilRoot({Object result}) {
    if (Navigator.of(context).canPop()) {
      pop();
      popUntilRoot();
    }
}
Vinesh Raju
quelle
0
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);
}
sj
quelle