Урок 5. Навигация и маршрутизация в приложении, class Navigator

Редкое приложение может обойтись одним окном или одной страницей. Во Flutter и то и другое – виджеты. Для переключения между окнами или виджетами нужно использовать Navigator.

Navigator – виджет-класс, позволяющий управлять стеком дочерних виджетов, т.е. открывать, закрывать и переключать окна или страницы. Когда мы используем MaterialApp, то экземпляр класса Navigator уже создан, и его не надо объявлять с помощью слова new.
А можно просто вызывать методы, для управления стеком виджетов:

В этом уроке мы рассмотрим некоторые основные возможности класса Navigator:

  1. Открытие нового окна и возврат к предыдущему.
  2. Использование маршрутов для навигации – routes.
  3. Передача параметров в маршруте с помощью события onGenerateRoute.
  4. Открытие диалогового окна.
  5. Анимация диалогового окна.
  6. Возвращаемое значение из диалогового окна.

1. Открытие нового окна и возврат к предыдущему

Чтобы открыть новое окно, нам нужно добавить в стек маршрутов новый маршрут. Это можно сделать с помощью Navigator.push, с указанием двух обязательных параметров: context и виджета MaterialPageRoute (или PageRouteBuilder).

Чтобы вернуться к предыдущему окну, используем метод Navigator.pop.

Создадим простой пример из двух окон.

В главном окне у нас будет кнопка, при нажатии на которую выполнится код «открытия окна»:

Класс MaterialPageRoute позволяет открыть полноэкранное окно с эффектом присущим для вашей мобильной системы, это простой и удобный способ. Можно воспользоваться другим виджетом PageRouteBuilder, он более сложный по конструкции, мы рассмотрим его в конце этого урока.

Во втором окне будет кнопка возвращения к первому окну с помощью:

class Navigator.push, class Navigator.pop

В виджете AppBar кнопка возврата добавляется автоматически при использовании Navigator.push, так же автоматически обрабатывается событие системной кнопки «Назад» (Back).

Листинг кода примера из двух окон

Минус такого подхода в том, что в большом приложении с большим количеством классов и виджетов, управлять такой структурой будет очень сложно. В каждый файл где вы будет использовать тот или иной виджет «окна» вам придется подключать его через import, и в случае замены на другой производить переименование виджета во всем проекте.

2. Использование маршрутов для навигации – routes

Поэтому чтобы избавиться от вышеуказанных проблем нужно использовать маршруты. Имена маршрутов принято использовать как пути в директориях: '/', '/client', '/client/123', и т.п.

Маршрут главного окна по умолчанию: '/'.

Когда в предыдущем примере в параметре home мы указали виджет MainScreen() – тем самым мы задали маршрут '/'.

Зададим маршруты в виджете MaterialApp через параметр routes.

Теперь параметр home со значением MainScreen() – можно удалить.

Если нам нужно изменить маршрут по умолчанию, при открытии приложения, нужно указать параметр initialRoute со значением маршрута, к примеру: initialRoute: '/second'.

Для открытия окна по маршруту нужно использовать Navigator.pushNamed.

Сделаем замену кода открытия окна с использованием маршрута:

Для возвращения ничего менять в коде не надо, оставляем Navigator.pop(context);

Листинг кода, пример с маршрутами:

3. Передача параметров в маршруте с помощью события onGenerateRoute

Следующая проблема, которую нужно решить – это передача параметров в маршруте. Например мы хотим передавать, в некоторых случает, число во второй виджет.
К примеру с помощью такого маршрута '/second/123'.

Если в предыдущем примере мы вызовем маршрут '/second/123' – то мы ничего не откроем: такого маршрута нет. Так как прописать все такие маршруты невозможно, то мы должны добавить обработчик onGenerateRoute в виджете MaterialApp:

Маршрут '/second' в параметре routes можно было бы убрать, нужно только правильно написать исключение на отсутствие параметра path[2]. Но в нашем примере мы оставим его.

Передача параметров в маршруте с помощью события onGenerateRoute

Листинг кода, пример с передачей параметров в маршруте:

4. Открытие диалогового окна

С помощью класса Navigator можно так же открывать диалоговые или всплывающие окна.

Создадим диалоговое окно с помощью виджет-класса PageRouteBuilder и параметром opaque: false.

Открытие диалогового окна

Листинг кода, открытия диалогового окна:

5. Анимация диалогового окна

Открывающиеся окна можно проанимировать, для этого нужно добавить параметр transitionsBuilder в виджет PageRouteBuilder

Нижние подчеркивания играют роль переменных, т.е. вместо «_» и «__» можно было бы задать «varA» и «varB».

Так как мы не используем эти переменные, а в параметрах должны быть указаны названия для них – мы присвоили им названия «_» и «__», визуально они выглядят как прочерк.

Интересным моментом является то что можно комбинировать анимации – как бы вкладывать их друг в друга.

Объединим две анимации: изменения прозрачности и увеличения размера.

Анимация при открытии диалогового окна

6. Возвращаемое значение из диалогового окна

Чтобы получить какое-то значение из диалогового окна, нужно в функции pop после context добавить значение, которое мы будем возвращать. Тип значения может быть любым.
Для нашего примера пусть будет: Navigator.pop(context,true);

Но чтобы получить значение нужно добавить: await перед Navigator и async в RaisedButton:

Возвращаемое значение из диалогового окна

Полный листинг кода