Навигация и маршрутизация во Flutter

В этом разделе будут представлены механизмы навигации и маршрутизации во Flutter, включая переходы между страницами, передачу параметров и именованные маршруты.


Основы Navigator

Flutter использует Navigator для управления страницами, реализуя переходы между страницами на основе стековой структуры.

Пример: базовая навигация по страницам

// Перейти на новую страницу
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// Вернуться на предыдущую страницу
Navigator.of(context).pop();

// Вернуться с результатом
Navigator.of(context).pop('Returned data');

// Заменить текущую страницу (нельзя вернуться назад)
Navigator.of(context).pushReplacement(
  MaterialPageRoute(
    builder: (context) => const HomePage(),
  ),
);

// Вернуться на корневую страницу
Navigator.of(context).popUntil((route) => route.isFirst);

MaterialPageRoute против CupertinoPageRoute

Пример: Анимации перехода между страницами на разных платформах

// Стиль Android - поднимается снизу
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// Стиль iOS - выезжает справа
Navigator.of(context).push(
  CupertinoPageRoute(
    builder: (context) => const DetailPage(),
  ),
);

// Пользовательский эффект перехода
Navigator.of(context).push(
  PageRouteBuilder(
    pageBuilder: (context, animation, secondaryAnimation) {
      return const DetailPage();
    },
    transitionsBuilder: (context, animation, secondaryAnimation, child) {
      // Эффект плавного появления/исчезновения
      return FadeTransition(
        opacity: animation,
        child: child,
      );
    },
    transitionDuration: const Duration(milliseconds: 300),
  ),
);

Передача параметров страницы

< h2 class="example">Пример: Передача параметров на новую страницу
// Перейти на страницу деталей и передать параметры
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => ProductDetailPage(productId: 123),
  ),
);

// Страница деталей получает параметры
class ProductDetailPage extends StatelessWidget {
  final int productId;

  const ProductDetailPage({
    super.key,
    required this.productId,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Product $productId')),
      body: Center(child: Text('ID товара: $productId')),
    );
  }
}

// Передать несколько параметров
class UserProfilePage extends StatelessWidget {
  final String name;
  final int age;

  const UserProfilePage({
    super.key,
    required this.name,
    required this.age,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(Домашняя страница $name)),
      body: Center(child: Text('Возраст: $age')),
    );
  }
}

// Переход
Navigator.of(context).push(
  MaterialPageRoute(
    builder: (context) => const UserProfilePage(
      name: 'Чжан Сань',
      age: 25,
    ),
  ),
);

Именованный маршрут

Использование именованных маршрутов может упростить настройку переходов между страницами.

Пример: Конфигурация именованных маршрутов

void main() {
  runApp(
    MaterialApp(
      // Определить таблицу маршрутизации
      initialRoute: '/',
      routes: {
        '/': (context) => const HomePage(),
        '/detail': (context) => const DetailPage(),
        '/user': (context) => const UserPage(),
        '/settings': (context) => const SettingsPage(),
      },
    ),
  );
}

// Переход
Navigator.pushNamed(context, '/detail');

// Навигация с параметрами
Navigator.pushNamed(context, '/user', arguments: {'name': 'Zhang San', 'age': 25});

// Получить параметры на целевой странице
class DetailPage extends StatelessWidget {
  const DetailPage({super.key});

  @override
  Widget build(BuildContext context) {
    // Получить переданные параметры
    final args = ModalRoute.of(context)?.settings.arguments as Map?;

    return Scaffold(
      appBar: AppBar(title: const Text('Страница деталей')),
      body: Center(
        child: Text(Аргументы: $args),
      ),
    );
  }
}

Другой способ передачи значений при маршрутизации

Пример: onGenerateRoute

MaterialApp(
  onGenerateRoute: (settings) {
    // Возвращать разные страницы в зависимости от имени маршрута
    switch (settings.name) {
      case '/':
        return MaterialPageRoute(
          builder: (_) => const HomePage(),
        );
      case '/detail':
        // Получить параметры из аргументов
        final args = settings.arguments as Map<String, dynamic>?;
        return MaterialPageRoute(
          builder: (_) => DetailPage(
            id: args?['id'] ?? 0,
            title: args?['title'] ?? '',
          ),
        );
      case '/product':
        final productId = settings.name?.split('/').last;
        return MaterialPageRoute(
          builder: (_) => ProductPage(id: productId ?? ''),
        );
      default:
        return MaterialPageRoute(
          builder: (_) => const NotFoundPage(),
        );
    }
  },
)

Для простых приложений достаточно базового Navigator.push; для средних и крупных приложений рекомендуется использовать именованные маршруты или библиотеки управления маршрутизацией для централизованного управления страницами.

Другие расширения