Navigation Approaches Overview
- Direct component switching - Similar to layout replacement in Android, where components are swapped directly (not recommended)
- Route-based navigation
- Basic routing with parameters (common approach)
- Using
Navigator.push()orNavigator.of(context).push()for navigation and parameter passing withMaterialPageRoute(builder: (context) => TargetWidget(param: "value")) - Using
Navigator.pop()orNavigator.of(context).pop()for returning, similar to Android's onBackPressed()
- Using
- Named routing with parameters (recommended)
- Standard named routing with direct parameter passing (most common and flexible)
- Register pages under MaterialApp's routes property
- Use
Navigator.pushNamed(context, "route_name", arguments: params)for navigation - Retrieve parameters via
ModalRoute.of(context)!.settings.arguments
- Custom onGenerateRoute parameter extraction (enables universal handling)
- No need to register routes in routes property
- Specify parameter processing for specific route jumps
- Still uses
Navigator.pushNamed(context, "route_name", arguments: params)but processed through onGenerateRoute
- Standard named routing with direct parameter passing (most common and flexible)
- Route replacement
- Root navigation
- Basic routing with parameters (common approach)
Direct Component Switching Example
import 'package:flutter/material.dart';
/// Tab page switching implementation
class TabNavigationExample extends StatefulWidget {
const TabNavigationExample({Key? key}) : super(key: key);
@override
_TabNavigationExampleState createState() => _TabNavigationExampleState();
}
class _TabNavigationExampleState extends State<TabNavigationExample> {
int selectedIndex = 0;
List<Widget> screenList = [
HomePage(),
CategoryPage(),
SettingsPage(),
ProfilePage(),
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("App Navigation")),
body: screenList[selectedIndex],
bottomNavigationBar: BottomNavigationBar(
type: BottomNavigationBarType.fixed,
onTap: (int index) {
setState(() {
this.selectedIndex = index;
});
},
currentIndex: selectedIndex,
fixedColor: Colors.blue,
iconSize: 24,
selectedFontSize: 14,
unselectedFontSize: 12,
items: [
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: "Home",
),
BottomNavigationBarItem(
icon: Icon(Icons.category),
label: "Category"
),
BottomNavigationBarItem(
icon: Icon(Icons.settings),
label: "Settings"
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: "Profile"
),
],
),
);
}
}
Basic Route Navigation with Parameters
Core APIs:
Navigator.push()orNavigator.of(context).push()for navigation and parameter pasingNavigator.pop()for returning
import 'package:flutter/material.dart';
void main() {
runApp(const MaterialApp(
title: 'Basic Navigation Example',
home: SourceScreen(),
));
}
class SourceScreen extends StatelessWidget {
const SourceScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Source Screen'),
),
body: Center(
child: ElevatedButton(
child: const Text('Navigate Forward'),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => const TargetScreen()),
// For parameter passing:
// MaterialPageRoute(builder: (context) => const TargetScreen(data: "Hello Flutter")),
);
},
),
),
);
}
}
class TargetScreen extends StatelessWidget {
final String data;
const TargetScreen({this.data = "", Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Target Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pop(context);
},
child: const Text('Return Back'),
// Using received parameter:
// child: Text(this.data),
),
),
);
}
}
Named Route Navigation with Parameters
Simple Named Route (No Parameters)
Requirements:
- Register pages in MaterialApp's routes
- Use
Navigator.pushNamed(context, "route_name")for navigattion
import 'package:flutter/material.dart';
void main() {
runApp(const AppWithNamedRoutes());
}
class AppWithNamedRoutes extends StatelessWidget {
const AppWithNamedRoutes({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Named Routes Demo",
initialRoute: "/",
routes: {
"/":(context) => InitialScreen(),
"/destination":(context) => DestinationScreen(),
},
);
}
}
class InitialScreen extends StatelessWidget {
const InitialScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Initial Screen")),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(context, '/destination');
},
child: const Text('Navigate to Destination'),
),
),
);
}
}
class DestinationScreen extends StatelessWidget {
const DestinationScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Destination Screen")),
body: Center(
child: ElevatedButton(
onPressed: (){
Navigator.pop(context);
},
child: Text("Return Back"),
),
),
);
}
}
Named Route with Parameter Passing
Requirements:
- Register pages in MaterialApp's routes
- Use
Navigator.pushNamed(context, "route_name", arguments: params)for navigation - Receive parameters via
ModalRoute.of(context)!.settings.arguments
import 'package:flutter/material.dart';
void main() {
runApp(const AppWithParameterizedRoutes());
}
class AppWithParameterizedRoutes extends StatelessWidget {
const AppWithParameterizedRoutes({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "Parameterized Routes Demo",
initialRoute: "/",
routes: {
"/":(context) => InitialScreenWithParams(),
"/destination":(context) => DestinationScreenWithParams(),
},
);
}
}
class InitialScreenWithParams extends StatelessWidget {
const InitialScreenWithParams({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Initial Screen")),
body: Center(
child: ElevatedButton(
onPressed: () {
Map<String, dynamic> parameters = {
"message": "This is passed parameter"
};
Navigator.pushNamed(context, '/destination', arguments: parameters);
},
child: const Text('Navigate with Parameters'),
),
),
);
}
}
class DestinationScreenWithParams extends StatelessWidget {
const DestinationScreenWithParams({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
Map<String, dynamic> receivedParams = ModalRoute.of(context)!.settings.arguments as Map<String, dynamic>;
return Scaffold(
appBar: AppBar(title: Text("Destination Screen")),
body: Center(
child: Container(
height: 200,
width: 200,
child: Column(
children: [
Text("${receivedParams["message"]}"),
ElevatedButton(
onPressed: (){
Navigator.pop(context);
},
child: Text("Return Back"),
),
],
),
),
),
);
}
}
Advanced Named Route with onGenerateRoute
Features:
- No need to register in routes property
- Specific parameter handling for route jumps
- Uses constructor-based parameter passing through unified management
Universal onGenerateRoute Implementation
import 'package:flutter/material.dart';
void main() => runApp(MyApplication());
class MyApplication extends StatelessWidget {
final Map<String, WidgetBuilder> routeRegistry = {
"/":(context) => HomeScreen(),
"/details" : (context, {arguments}) => DetailsScreen(arguments: arguments),
};
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: (RouteSettings settings) {
String? currentRoute = settings.name;
Function? routeBuilder = this.routeRegistry[currentRoute] as Function;
if(routeBuilder != null) {
if(settings.arguments != null){
return MaterialPageRoute(
builder:(context) => routeBuilder(context, arguments:settings.arguments)
);
} else {
return MaterialPageRoute(
builder:(context) => routeBuilder(context)
);
}
}
return null;
},
title: 'Advanced Navigation System',
home: const HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Home Screen'),
),
body: Center(
child: ElevatedButton(
onPressed: () {
Navigator.pushNamed(
context,
'/details',
arguments: RouteParameters(
'Received Title',
'Message extracted via onGenerateRoute function.',
),
);
},
child: const Text('Navigate to Details'),
),
),
);
}
}
class DetailsScreen extends StatelessWidget {
final RouteParameters? arguments;
const DetailsScreen({this.arguments, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text("Details Screen")),
body: Center(
child: Container(
height: 200,
width: 400,
child: Column(
children: [
Text("Title: ${arguments?.title}"),
Text("Message: ${arguments?.message}"),
ElevatedButton(
onPressed: (){
Navigator.pop(context);
},
child: Text("Return Back"),
),
],
),
),
),
);
}
}
class RouteParameters {
final String title;
final String message;
RouteParameters(this.title, this.message);
}
Reusable Route Configuration
import 'package:flutter/material.dart';
// Define route registry
final Map<String, Function> appRoutes = {
"/":(context) => HomeScreen(),
"/details" : (context, {arguments}) => DetailsScreen(arguments: arguments),
// Add new routes here as needed
};
// Universal route generator
var universalRouteGenerator = (RouteSettings settings) {
String? routeName = settings.name;
Function? routeBuilder = appRoutes[routeName];
Object? routeArgs = settings.arguments;
if(routeBuilder != null) {
if(routeArgs != null) {
final Route route = MaterialPageRoute(builder: (context) {
return routeBuilder(context, arguments: routeArgs);
});
return route;
} else {
return MaterialPageRoute(builder: (context) => routeBuilder(context));
}
}
};
Use in main.dart:
import 'package:flutter/material.dart';
import 'package:myapp/config/routes_config.dart';
void main() => runApp(MyApplication());
class MyApplication extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
onGenerateRoute: universalRouteGenerator,
title: 'Navigation with Universal Handler',
home: const HomeScreen(),
);
}
}