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ć RoutePredicate
lub mieć jakąkolwiek funkcję removeAll.
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ć RoutePredicate
lub mieć jakąkolwiek funkcję removeAll.
Odpowiedzi:
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 /login
trasy, którą pchnąłem.
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 .
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ę.
Innym rozwiązaniem jest użycie pushAndRemoveUntil()
. Aby usunąć wszystkie inne trasy, użyjModalRoute.withName('/')
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (BuildContext context) => Login()),
ModalRoute.withName('/')
);
Źródła: https://api.flutter.dev/flutter/widgets/NavigatorState/pushAndRemoveUntil.html
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.
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.
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
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());
}
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();
}
}