Расскажи про опыт работы с навигацией во Flutter

«Расскажи про опыт работы с навигацией во Flutter» — вопрос из категории Навигация, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Работал с различными подходами к навигации, от простых до сложных, в зависимости от требований проекта.

1. Императивная навигация (Navigator 1.0): Использую для простых приложений или внутри отдельных модулей. Быстро и понятно.

// Переход с передачей данных
Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailsScreen(item: selectedItem),
  ),
);

// Возврат с результатом
final result = await Navigator.push(
  context,
  MaterialPageRoute(builder: (context) => SelectionScreen()),
);
if (result != null) { /* обработка результата */ }

2. Именованные маршруты (Named Routes): Удобны для централизованного управления маршрутами в MaterialApp.

MaterialApp(
  initialRoute: '/',
  routes: {
    '/': (context) => HomeScreen(),
    '/details': (context) => DetailsScreen(),
    '/profile': (context) => ProfileScreen(),
  },
  onGenerateRoute: (settings) {
    // Динамическая генерация маршрута, например, для '/user/:id'
    if (settings.name?.startsWith('/user/') ?? false) {
      final userId = settings.name!.split('/').last;
      return MaterialPageRoute(
        builder: (context) => UserScreen(userId: userId),
      );
    }
    return null;
  },
);

3. Декларативная навигация (Navigator 2.0 / Router API): Применял в проектах с глубокими ссылками, веб-поддержкой и сложным состоянием навигации (например, приложение с вкладками и модальными окнами). Использовал пакет go_router, который сильно упрощает работу с Router API.

final _router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => HomeScreen(),
      routes: [
        GoRoute(
          path: 'details/:id', // Глубокие ссылки /details/123
          builder: (context, state) {
            final id = state.pathParameters['id']!;
            return DetailsScreen(itemId: id);
          },
        ),
      ],
    ),
  ],
  redirect: (context, state) {
    // Логика редиректа, например, проверка авторизации
    final isLoggedIn = authService.isLoggedIn;
    final goingToLogin = state.location == '/login';
    if (!isLoggedIn && !goingToLogin) return '/login';
    if (isLoggedIn && goingToLogin) return '/';
    return null;
  },
);
// В MaterialApp
MaterialApp.router(
  routerConfig: _router,
)

4. Управление состоянием навигации: Интегрировал навигацию с менеджером состояния (например, Riverpod). Состояние приложения (выбранный элемент, фильтры) определяет текущий стек страниц, что делает логику предсказуемой и тестируемой.

Опыт включает: реализацию глубоких ссылок для пуш-уведомлений, кастомные переходы с PageRouteBuilder, защиту маршрутов (guards) и сохранение состояния при навигации с AutomaticKeepAliveClientMixin.