Bỏ qua để đến nội dung

🗺️ Named Routes

Named routes cho phép định nghĩa routes bằng tên thay vì tạo MaterialPageRoute mỗi lần:

Navigator.pushNamed(context, '/profile');

MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/profile': (context) => ProfileScreen(),
'/settings': (context) => SettingsScreen(),
'/login': (context) => LoginScreen(),
},
)

Navigator.pushNamed(context, '/profile');
Navigator.pushReplacementNamed(context, '/home');
Navigator.pushNamedAndRemoveUntil(
context,
'/home',
(route) => false, // Xóa tất cả
);
Navigator.popAndPushNamed(context, '/profile');

Navigator.pushNamed(
context,
'/profile',
arguments: {'userId': 123, 'name': 'John'},
);
// Hoặc với object
Navigator.pushNamed(
context,
'/profile',
arguments: User(id: 123, name: 'John'),
);
class ProfileScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
// Nhận arguments
final args = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
final userId = args['userId'];
// Hoặc với object
// final user = ModalRoute.of(context)!.settings.arguments as User;
return Scaffold(
appBar: AppBar(title: Text('User $userId')),
);
}
}

Xử lý routes động với arguments:

MaterialApp(
initialRoute: '/',
onGenerateRoute: (settings) {
switch (settings.name) {
case '/':
return MaterialPageRoute(builder: (_) => HomeScreen());
case '/profile':
final args = settings.arguments as Map<String, dynamic>?;
return MaterialPageRoute(
builder: (_) => ProfileScreen(userId: args?['userId']),
);
case '/product':
final productId = settings.arguments as int;
return MaterialPageRoute(
builder: (_) => ProductScreen(productId: productId),
);
default:
return MaterialPageRoute(builder: (_) => NotFoundScreen());
}
},
)

Xử lý route không tồn tại:

MaterialApp(
onUnknownRoute: (settings) {
return MaterialPageRoute(
builder: (_) => NotFoundScreen(),
);
},
)

Best practice: định nghĩa route names là constants:

class AppRoutes {
static const home = '/';
static const login = '/login';
static const profile = '/profile';
static const settings = '/settings';
static const productDetail = '/product';
}
// Sử dụng
Navigator.pushNamed(context, AppRoutes.profile);

class AppRouter {
static const home = '/';
static const login = '/login';
static const profile = '/profile';
static const product = '/product';
static Route<dynamic> generateRoute(RouteSettings settings) {
switch (settings.name) {
case home:
return MaterialPageRoute(builder: (_) => HomeScreen());
case login:
return MaterialPageRoute(builder: (_) => LoginScreen());
case profile:
final userId = settings.arguments as int?;
return MaterialPageRoute(
builder: (_) => ProfileScreen(userId: userId ?? 0),
);
case product:
final product = settings.arguments as Product;
return MaterialPageRoute(
builder: (_) => ProductDetailScreen(product: product),
);
default:
return MaterialPageRoute(
builder: (_) => Scaffold(
body: Center(child: Text('Route not found: ${settings.name}')),
),
);
}
}
}
// main.dart
MaterialApp(
initialRoute: AppRouter.home,
onGenerateRoute: AppRouter.generateRoute,
)
class NavigationService {
static void goToProfile(BuildContext context, int userId) {
Navigator.pushNamed(context, AppRoutes.profile, arguments: userId);
}
static void goToProduct(BuildContext context, Product product) {
Navigator.pushNamed(context, AppRoutes.product, arguments: product);
}
static void logout(BuildContext context) {
Navigator.pushNamedAndRemoveUntil(
context,
AppRoutes.login,
(route) => false,
);
}
}

  • Không type-safe (arguments là dynamic)
  • Khó refactor
  • Không hỗ trợ deep linking tốt

💡 Khuyến nghị: Dùng GoRouter cho apps phức tạp (xem bài tiếp theo)


Method Mô tả
pushNamed Navigate đến named route
pushReplacementNamed Replace với named route
pushNamedAndRemoveUntil Push và xóa stack
popAndPushNamed Pop và push named
Config Mục đích
routes Map tĩnh route → widget
onGenerateRoute Dynamic route handling
onUnknownRoute Route không tồn tại