Flutter Navigation Fundamentals: Basic Routing, Named Routes, and Parameter Passing Techniques

Navigation Approaches Overview

  1. Direct component switching - Similar to layout replacement in Android, where components are swapped directly (not recommended)
  2. Route-based navigation
    1. Basic routing with parameters (common approach)
      • Using Navigator.push() or Navigator.of(context).push() for navigation and parameter passing with MaterialPageRoute(builder: (context) => TargetWidget(param: "value"))
      • Using Navigator.pop() or Navigator.of(context).pop() for returning, similar to Android's onBackPressed()
    2. 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
    3. Route replacement
    4. Root navigation

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() or Navigator.of(context).push() for navigation and parameter pasing
  • Navigator.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(),
    );
  }
}

Tags: Flutter Navigation Routing Mobile Development Cross Platform

Posted on Fri, 19 Jun 2026 16:31:01 +0000 by panoramical