Навигация и маршрутизация во 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);
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),
),
);
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,
),
),
);
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),
),
);
}
}
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(),
);
}
},
)
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; для средних и крупных приложений рекомендуется использовать именованные маршруты или библиотеки управления маршрутизацией для централизованного управления страницами.