Flutter AppBar Drawer BottomNav
Most apps have more than one screen. Navigation is how you move between them. Flutter uses a stack-based system called the Navigator to manage screens, and a route system to define paths between them.
How Flutter Navigation Works
Flutter's Navigator works like a stack of plates. Each new screen you open goes on top. When you go back, the top plate is removed and you see the one below.
NAVIGATOR STACK ┌─────────────────────┐ ← Active (user sees this) │ Product Detail │ ├─────────────────────┤ │ Product List │ ├─────────────────────┤ │ Home Screen │ ← Bottom of stack └─────────────────────┘ Push → add a screen on top Pop → remove the top screen (go back)
Basic Navigation — Push and Pop
Push: Go to a New Screen
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => DetailScreen()),
);
},
child: Text('View Details'),
)
Pop: Go Back
ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: Text('Go Back'),
)
Passing Data Between Screens
Pass data to the next screen through the constructor, just like passing arguments to a function.
// Screen 1 — Send data
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetail(productName: 'Running Shoes', price: 2499),
),
);
// Screen 2 — Receive data
class ProductDetail extends StatelessWidget {
final String productName;
final int price;
const ProductDetail({required this.productName, required this.price});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(productName)),
body: Center(child: Text('Price: ₹$price')),
);
}
}
Returning Data Back to Previous Screen
// On Screen 2 — Pop with a result Navigator.pop(context, 'Item added to cart'); // On Screen 1 — Await the result String? result = await Navigator.push( context, MaterialPageRoute(builder: (context) => Screen2()), ); print(result); // 'Item added to cart'
Named Routes
For larger apps, named routes keep navigation clean and centralized. You define all route paths in one place.
App routes map: ──────────────────────────────────── '/' → HomeScreen '/login' → LoginScreen '/profile' → ProfileScreen '/details' → DetailScreen
MaterialApp(
initialRoute: '/',
routes: {
'/': (context) => HomeScreen(),
'/login': (context) => LoginScreen(),
'/profile': (context) => ProfileScreen(),
},
)
// Navigate using the route name Navigator.pushNamed(context, '/profile'); // Go back Navigator.pop(context);
pushNamed vs push
| Method | Best For |
|---|---|
Navigator.push() | Small apps, passing constructor data easily |
Navigator.pushNamed() | Larger apps, clean route management |
Replace or Clear the Stack
pushReplacement — Replace Current Screen
Use this after login: replace the login screen with the home screen so the user cannot tap Back to return to login.
Navigator.pushReplacement( context, MaterialPageRoute(builder: (context) => HomeScreen()), );
pushAndRemoveUntil — Clear Entire Stack
Use this for logout: remove all screens and start fresh.
Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (context) => LoginScreen()), (route) => false, // false removes all previous routes );
After logout: Stack before: [Login] [Home] [Profile] [Settings] Stack after: [Login] ← only login remains
go_router — Modern Navigation Package
For advanced apps with deep links and complex routing, the go_router package (officially recommended by Flutter) offers a URL-style navigation system.
Route definitions: ────────────────────────────────── /home → HomeScreen /product/:id → ProductDetail (with dynamic ID) /cart → CartScreen
// Add to pubspec.yaml
dependencies:
go_router: ^latest_version
// Navigate
context.go('/product/42');
context.go('/cart');
Navigation Best Practices
- Use
pushReplacementafter login so users cannot go back to the login screen. - Prefer named routes or
go_routeras the app grows beyond 3-4 screens. - Always pass only the data a screen needs — avoid passing entire objects when one field will do.
- Use
pushAndRemoveUntilon logout to clear all session-specific screens from the stack.
