Ответ
Navigator 1.0 (императивный) — это классический стековый навигатор, управляемый прямыми командами push и pop. Он прост для понимания, но сложен для синхронизации с состоянием приложения (например, с глубокими ссылками).
// Императивный подход
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const DetailsScreen()),
);
Navigator 2.0 (декларативный) — это более новая парадигма, где стек страниц (pages) является частью состояния вашего приложения. Вы управляете навигацией, изменяя список страниц, а Flutter сам анимирует переходы.
class AppRouter extends StatefulWidget {
const AppRouter({super.key});
@override
State<AppRouter> createState() => _AppRouterState();
}
class _AppRouterState extends State<AppRouter> {
// Состояние навигации — список страниц
List<Page<dynamic>> _pages = [const MaterialPage(child: HomeScreen())];
void _openDetails() {
setState(() {
_pages = [..._pages, const MaterialPage(child: DetailsScreen())];
});
}
@override
Widget build(BuildContext context) {
return Navigator(
pages: _pages,
onPopPage: (route, result) {
if (!route.didPop(result)) return false;
// Обновляем состояние при попытке возврата
setState(() => _pages.removeLast());
return true;
},
);
}
}
Ключевые преимущества Navigator 2.0:
- Полный контроль: Стек страниц — часть вашего состояния, что упрощает интеграцию с state-менеджерами (Bloc, Riverpod).
- Глубокие ссылки: Прямая синхронизация URL (в веб) или роута с состоянием навигации.
- Сложные сценарии: Упрощает реализацию вложенных навигаторов, модальных потоков.
На практике для большинства приложений я использую пакеты-надстройки, которые реализуют Navigator 2.0, такие как go_router или auto_route. Они скрывают boilerplate-код, предоставляя удобный API для объявления роутов и работы с глубокими ссылками.
Ответ 18+ 🔞
Слушай, давай разберем эту дичь с навигаторами во Flutter, а то у некоторых от этих версий уже глаза на лоб лезут, как у совы на солярисе.
Вот представь: Navigator 1.0 — это как старый добрый пульт от телевизора с кнопками. Хочешь переключить канал? Тыкаешь push — и поехала новая страница. Назад? Жмешь pop — и вернулся. Всё просто, прямолинейно, императивно. Но есть одна, блядь, проблема: синхронизировать этот ручной переключатель каналов с состоянием всего твоего приложения — это тот ещё геморрой. Глубокие ссылки? Ох, ёпта... Тут уже начинается ад.
// Старая школа. Ткнул и поехал.
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => const DetailsScreen()),
);
А теперь смотри сюда, Navigator 2.0 — это уже не пульт, а умный плейлист. Ты не тыкаешь кнопки, а просто объявляешь: «Слушай, Flutter, вот список страниц, которые должны быть у меня в стеке сейчас». И он сам, хитрая жопа, всё красиво анимирует, добавляет и убирает. Стек страниц становится частью состояния твоего виджета. Сам от себя охуел, когда это понял.
class AppRouter extends StatefulWidget {
const AppRouter({super.key});
@override
State<AppRouter> createState() => _AppRouterState();
}
class _AppRouterState extends State<AppRouter> {
// Вот он, весь наш стек. Храним как состояние. Красота!
List<Page<dynamic>> _pages = [const MaterialPage(child: HomeScreen())];
void _openDetails() {
setState(() {
// Говорим: "Добавь ещё одну страницу в конец"
_pages = [..._pages, const MaterialPage(child: DetailsScreen())];
});
}
@override
Widget build(BuildContext context) {
return Navigator(
pages: _pages, // Скармливаем стеку наш список
onPopPage: (route, result) {
if (!route.didPop(result)) return false;
// А когда юзер жмёт назад, просто удаляем последнюю страницу из состояния
setState(() => _pages.removeLast());
return true;
},
);
}
}
И в чём же, блядь, кайф?
- Полный контроль, ёб твою мать! Твой стек теперь не какая-то тёмная магия, а обычный список в твоём стейте. Захотел — синхронизировал с Bloc или Riverpod, и нет проблем.
- Глубокие ссылки. Это просто пиздец как удобно. URL в вебе или роут в мобилке теперь напрямую отражают твой стек. Никаких костылей.
- Сложные сценарии. Вложенные навигаторы, модальные окна, которые должны влиять на историю — с Navigator 2.0 это перестаёт быть квестом на выживание.
Но честно? Писать весь этот boilerplate-код вручную — это, конечно, овердохуища работы. Поэтому все адекватные люди, чувак, берут готовые решения поверх 2.0. go_router или auto_route — вот это реальные пацаны. Они под капотом используют эту декларативную мощь, но дают тебе такой удобный API, что просто волнение ебать. Объявил роуты, настроил глубокие ссылки — и не паришься.