Я хочу разработать кнопку выхода, которая отправит меня в маршрут входа и удалит все остальные маршруты из навигатора. В документации, похоже, не объясняется, как создать RoutePredicate или какую-либо функцию removeAll.

chrislondon

Ответов: 13

Ответы (13)

Мне удалось это сделать с помощью следующего кода:

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

The secret here is using a RoutePredicate that always returns false (Route route) => false. In this situation it removes all of the routes except for the new /login route I pushed.

Не уверен, правильно ли я делаю

, но это подходит моему варианту использования, пока не появится корневой виджет

void popUntilRoot({Object result}) {
    if (Navigator.of(context).canPop()) {
      pop();
      popUntilRoot();
    }
}

Если вы используете namedRoutes, вы можете сделать это просто:

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

Где "/ login" - это маршрут, который вы хотите поместить в стек маршрутов.

Обратите внимание:

Этот оператор удаляет все маршруты в стеке и делает проталкиваемый корневым.

В моем случае была эта картина Страница 1 (Главная) -> Страница 2 -> Страница 3 -> Страница 4.

Когда мне нужно было перейти на страницу 4, страницы 2 и страница 3 возврата не должны были появляться, но мне пришлось снова перейти на страницу 1. На этом этапе, перейдя на страницу 4, я сделал:

Navigator.pushAndRemoveUntil(
              context,
              MaterialPageRoute(
                  builder: (BuildContext context) =>
                      Workout()),
             (Route route) => route.isFirst);

Инструкции следующие: перейдите на страницу 4 (Тренировка) и удалите все предыдущие страницы до 1, то есть (Основная).

В вашем случае это может быть переключение с чего угодно на Логин, тогда:

Navigator.pushAndRemoveUntil(
              context,
              MaterialPageRoute(
                  builder: (BuildContext context) =>
                      Login()),
             (Route route) => false);

То есть заходим в Login и удаляем все предыдущие страницы, потому что там ложь.

Это работает для меня. На самом деле, я работал с bloc, но моя проблема заключалась в блоке экрана входа в систему. После выхода из системы он не обновлялся. В нем хранились данные предыдущей модели. Даже, я ввел неправильную запись. Это был главный экран.

Шаг 1:

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

где, UIData.initialRoute = "/" или "/ логин"

Шаг 2:

Работает обновить экран. Если вы работаете с Bloc, это вам очень поможет.

runApp(MyApp());

где, MyApp () - корневой класс.

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

Вот мой Метод выхода,

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 route) => false);
    //TODO: It's working as refresh the screen
    runApp(MyApp());
  }
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);
}

В моем случае это решение работает:

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

Другой альтернативой является popUntil ()

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

Это отключит все маршруты, пока вы не вернетесь на указанный маршрут.

Другое решение - использовать pushAndRemoveUntil (). Чтобы удалить все остальные маршруты, используйте ModalRoute.withName ('/')

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

Ссылка: https://api.flutter.dev/flutter/widgets/NavigatorState/pushAndRemoveUntil.html

это можно сделать с помощью следующего фрагмента кода:

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

, если вы хотите удалить весь маршрут ниже переданного маршрута, RoutePredicate всегда возвращает false, например, (Route route) => false.

Я не знаю, почему никто не упомянул решение с использованием SchedularBindingInstance, немного поздно для вечеринки, я думаю, что это был бы правильный способ сделать это изначально ответил здесь

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

Приведенный выше код удаляет все маршруты и навигационные сообщения к '/ login', это также гарантирует, что все кадры будут отрисованы перед переходом к новому маршруту, запланировав обратный вызов

Если вы хотите вернуться к определенному экрану и не используете именованный маршрутизатор, вы можете использовать следующий подход

Пример:

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

С route is HomePage вы проверяете имя вашего виджета.

Сначала см. Ответ chrislondon, а затем знайте, что вы также можете сделать это, если у вас нет доступа к (контексту).

navigatorKey.currentState.pushNamedAndRemoveUntil('/login', (Route route) => false);  

2022 WebDevInsider