1. GoRouter Setup
# pubspec.yaml
dependencies:
go_router: ^14.0.0
final router = GoRouter(
initialLocation: '/',
routes: [
GoRoute(
path: '/',
builder: (context, state) => const HomePage(),
),
GoRoute(
path: '/products',
builder: (context, state) => const ProductListPage(),
routes: [
GoRoute(
path: ':id',
builder: (context, state) {
final id = state.pathParameters['id']!;
return ProductDetailPage(id: id);
},
),
],
),
GoRoute(
path: '/search',
builder: (context, state) {
final query = state.uri.queryParameters['q'] ?? '';
return SearchPage(query: query);
},
),
],
redirect: (context, state) {
final isLoggedIn = authNotifier.isLoggedIn;
if (!isLoggedIn && state.matchedLocation.startsWith('/dashboard')) {
return '/login';
}
return null;
},
);
2. Navigation
// Programmatic navigation
context.go('/products');
context.push('/products/123');
context.pop();
// Named routes
context.goNamed('productDetail', pathParameters: {'id': '123'});
3. Shell Route (Tab Navigation)
ShellRoute(
builder: (context, state, child) {
return MainShell(child: child);
},
routes: [
GoRoute(path: '/home', builder: (_, __) => const HomePage()),
GoRoute(path: '/explore', builder: (_, __) => const ExplorePage()),
GoRoute(path: '/profile', builder: (_, __) => const ProfilePage()),
],
);
class MainShell extends StatelessWidget {
final Widget child;
const MainShell({super.key, required this.child});
@override
Widget build(BuildContext context) {
return Scaffold(
body: child,
bottomNavigationBar: NavigationBar(
selectedIndex: _calculateIndex(GoRouterState.of(context).matchedLocation),
destinations: const [
NavigationDestination(icon: Icon(Icons.home), label: 'Home'),
NavigationDestination(icon: Icon(Icons.explore), label: 'Explore'),
NavigationDestination(icon: Icon(Icons.person), label: 'Profile'),
],
onDestinationSelected: (index) {
switch (index) {
case 0: context.go('/home');
case 1: context.go('/explore');
case 2: context.go('/profile');
}
},
),
);
}
}
Bài tiếp theo: State Management với Riverpod.