Flutter usuwa wszystkie trasy

107

Chcę opracować przycisk wylogowania, który wyśle ​​mnie do trasy logowania i usunie wszystkie inne trasy z Navigator. Dokumentacja nie wydaje się wyjaśniać, jak utworzyć RoutePredicatelub mieć jakąkolwiek funkcję removeAll.

chrislondon
źródło

Odpowiedzi:

277

Udało mi się to osiągnąć za pomocą następującego kodu:

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

Sekret polega na użyciu RoutePredicate, która zawsze zwraca wartość false (Route<dynamic> route) => false. W tej sytuacji usuwa wszystkie trasy z wyjątkiem nowej /logintrasy, którą pchnąłem.

chrislondon
źródło
1
Wielkie dzięki, udało się. Czy mógłbyś wysłać jakiś link, gdzie mogę zrozumieć więcej…
Pawan
Mam z tym problem! Na iOS, używając natywnego widoku jako widżetu, po użyciu twojej metody natywny widok nie usuwa się prawidłowo i nadal istnieje, w rezultacie mam widok, który nigdy nie będzie ponownie używany, działający w pewnym sensie w tle i niemożliwy do usunięcia . Wydaje się, że dzieje się tak tylko na urządzeniach z iOS.
Lorenzo Imperatrice
@LorenzoImperatrice Czy znalazłeś rozwiązanie tego problemu? Mam podobny problem
Mateusz Tylman
3
Mam otwarte instancje, nawet po użyciu tego. jakieś inne rozwiązanie, aby przesunąć ekran i usunąć resztę stosu?
Manoj MM
Jak możemy przekazywać argumenty za pomocą tego podejścia.
Developine
86

mogę zrobić z następującym fragmentem kodu:

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

jeśli chcesz usunąć całą trasę poniżej przekazanej trasy, RoutePredicate zawsze zwraca false , np. (Route route) => false .

Amir Khan
źródło
27

Inną alternatywą jest popUntil()

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

Spowoduje to wyłączenie wszystkich tras, dopóki nie wrócisz na nazwaną trasę.

nleslie
źródło
1
Wolę tę odpowiedź!
powieść nawet
13

Jeśli chcesz wrócić do określonego ekranu i nie używasz nazwanego routera, możesz skorzystać z następnego podejścia

Przykład:

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

Dzięki Route to HomePage sprawdzasz nazwę swojego widżetu.

Volodymyr Bilovus
źródło
co to jest NoAnimatedRoute? Nie mogę znaleźć klasy o takiej nazwie w Flutter
kashlo
@kashlo Nie zwracaj uwagi =) Po prostu moja implementacja może zamiast tego używać MaterialPageRoute. Ale zredagowałem odpowiedź, dzięki.
Volodymyr Bilovus
(Route <dynamic> route) => route.isFirst) Jeśli ktoś chce usunąć aż do pierwszej trasy.
Hussnain Haidar
7

Jeśli używasz namedRoutes, możesz to zrobić po prostu:

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

Gdzie „/ login” to trasa, którą chcesz umieścić na stosie tras.

Zauważ, że:

Ta instrukcja usuwa wszystkie trasy na stosie i sprawia, że ​​przekazana jedna jest katalogiem głównym.

Kelvin Mboto
źródło
5

Nie wiem, dlaczego nikt nie wspomniał o rozwiązaniu za pomocą SchedularBindingInstance , Trochę spóźniony na imprezę, myślę, że byłby to właściwy sposób, aby to zrobić pierwotnie odpowiedział tutaj

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

Powyższy kod usuwa wszystkie trasy i nawigacje do '/ login', co również zapewnia, że ​​wszystkie ramki są renderowane przed nawigacją do nowej trasy przez zaplanowanie wywołania zwrotnego

maheshmnj
źródło
2

To działa dla mnie. Właściwie pracowałem z blokiem, ale moim problemem był blok ekranu logowania. Nie aktualizował się po wylogowaniu. Przechowywał dane poprzedniego modelu. Nawet wpisałem zły wpis. Przechodził do ekranu głównego.

Krok 1:

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

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

Krok 2:

Działa, aby odświeżyć ekran. Jeśli pracujesz z Bloc, będzie to bardzo pomocne.

runApp(MyApp());

gdzie, MyApp() is the root class.

Kod klasy głównej (tj. 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());

Oto metoda My Logout ,

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());
  }
gwiazda rocka
źródło
0

Nie jestem pewien, czy robię to dobrze

ale to pasuje do mojego przypadku użycia poppingu do widgetu root

void popUntilRoot({Object result}) {
    if (Navigator.of(context).canPop()) {
      pop();
      popUntilRoot();
    }
}
Vinesh Raju
źródło
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
źródło