Routing and Multi-Screen Development in Flutter

Introduction

Modern mobile applications consist of multiple screens such as login, dashboard, profile, and settings. In Flutter, managing these screens is done using routing and navigation.

This beginner-friendly guide will help you understand:

  • Routing in Flutter

  • Multi-screen app structure

  • Navigation using Navigator

  • Passing data between screens

  • Named routes (recommended for large apps)

  • Real-world example with complete code

What is Routing in Flutter?

Routing refers to the process of navigating between different screens (widgets) in an app.

In Flutter:

  • Each screen = a Widget

  • Each screen is called a Route

  • Navigation is handled by the Navigator

Types of Routing in Flutter

1. Direct Routing (Using MaterialPageRoute)

  • Simple navigation

  • Good for small apps

2. Named Routing

  • Uses route names (strings)

  • Better for large applications

Understanding Navigator

The Navigator works like a stack (LIFO):

  • push() → Add new screen

  • pop() → Remove current screen

👉 Example: Home → Details → Checkout

Real-Time Example: Student App (Multi-Screen)

We will build a simple app with:

  1. Home Screen

  2. Student Detail Screen

  3. Result Screen

Step 1: Project Structure

Step 2: Main File (Routes Setup)

import 'package:flutter/material.dart';
import 'screens/home_screen.dart';
import 'screens/detail_screen.dart';
import 'screens/result_screen.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Student App',

      initialRoute: '/',

      routes: {
        '/': (context) => HomeScreen(),
        '/detail': (context) => DetailScreen(),
        '/result': (context) => ResultScreen(),
      },
    );
  }
}

Step 3: Home Screen

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  final TextEditingController nameController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("Home Screen")),
      body: Padding(
        padding: EdgeInsets.all(16),
        child: Column(
          children: [
            TextField(
              controller: nameController,
              decoration: InputDecoration(labelText: "Enter Name"),
            ),

            SizedBox(height: 20),

            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(
                  context,
                  '/detail',
                  arguments: nameController.text,
                );
              },
              child: Text("Go to Detail Screen"),
            ),
          ],
        ),
      ),
    );
  }
}

Step 4: Detail Screen (Receive Data)

import 'package:flutter/material.dart';

class DetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final String name =
    ModalRoute.of(context)!.settings.arguments as String;

    return Scaffold(
      appBar: AppBar(title: Text("Detail Screen")),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text("Student Name: $name"),

            SizedBox(height: 20),

            ElevatedButton(
              onPressed: () {
                Navigator.pushNamed(
                  context,
                  '/result',
                  arguments: "Pass",
                );
              },
              child: Text("Check Result"),
            ),
          ],
        ),
      ),
    );
  }
}

Step 5: Result Screen

import 'package:flutter/material.dart';

class ResultScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final String result =
    ModalRoute.of(context)!.settings.arguments as String;

    return Scaffold(
      appBar: AppBar(title: Text("Result Screen")),
      body: Center(
        child: Text(
          "Result: $result",
          style: TextStyle(fontSize: 22),
        ),
      ),
    );
  }
}

Flow of the App

  1. User enters name on Home Screen

  2. Navigates to Detail Screen with data

  3. Detail Screen displays name

  4. User navigates to Result Screen

  5. Result is displayed

Passing Data Between Screens

Send Data:

Navigator.pushNamed(
  context,
  '/detail',
  arguments: nameController.text,
);

Receive Data:

final String name = ModalRoute.of(context)!.settings.arguments as String;

Direct Routing Example (Alternative)

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => DetailScreen(),
  ),
);

Named Routes vs Direct Routes

Feature Direct Route Named Route
Simplicity Easy Moderate
Scalability Poor Excellent
Code Structure Scattered Centralized
Recommended Small apps Large apps

 

 

Best Practices for Multi-Screen Apps

✔ Use named routes for large projects
✔ Keep screens in separate files
✔ Pass only necessary data
✔ Avoid deep nested navigation
✔ Use meaningful route names
✔ Handle null safety properly

LAB TASK:

How to Set Up Your Flutter Project: The Car List App

Step 1: Create a New Flutter Project

Step 2: Organize the Project Structure

Step 3: Populate the Files

1. lib/models/car.dart

// lib/models/car.dart
class Car {
  final String id;
  final String name;
  final String imageUrl;
  final String description;

  Car({
    required this.id,
    required this.name,
    required this.imageUrl,
    required this.description,
  });
}

2. lib/data/dummy_data.dart

// lib/data/dummy_data.dart
import '../models/car.dart';

final List<Car> carList = [
  Car(
    id: '1',
    name: 'Tesla Model S',
    imageUrl: 'https://hips.hearstapps.com/hmg-prod/images/2025-tesla-model-s-2-672d42e16475f.jpg?crop=0.503xw:0.502xh;0.262xw,0.289xh&resize=980:*',
    description: 'Electric car with autopilot features.',
  ),
  Car(
    id: '2',
    name: 'BMW M4',
    imageUrl: 'https://upload.wikimedia.org/wikipedia/commons/thumb/e/e2/2021_BMW_M4_Competition_Automatic_3.0_Front.jpg/1200px-2021_BMW_M4_Competition_Automatic_3.0_Front.jpg',
    description: 'Sporty and powerful coupe.',
  ),
  Car(
    id: '3',
    name: 'Ford Mustang',
    imageUrl: 'https://images.prismic.io/carwow/c2d2e740-99e2-4faf-8cfa-b5a75c5037c0_ford-mustang-2024-lhd-front34static.jpg?auto=format&cs=tinysrgb&fit=max&q=60',
    description: 'Iconic American muscle car.',
  ),
];

 

3. lib/screens/home_screen.dart

// lib/screens/home_screen.dart
import 'package:flutter/material.dart';
import '../widgets/car_list_tile.dart';    // Import Car model

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('Available Cars')),
      body: ListView.builder(
        itemCount: carList.length,
        itemBuilder: (context, index) {
          final car = carList[index];
          return Card(
            margin: const EdgeInsets.all(8),
            child: ListTile(
              contentPadding: const EdgeInsets.all(10),
              leading: CircleAvatar(
                radius: 40,
                backgroundImage: NetworkImage(car.imageUrl),
              ),
              title: Text(car.name, style: const TextStyle(fontWeight: FontWeight.bold)),
              subtitle: Text(car.description, maxLines: 2, overflow: TextOverflow.ellipsis),
              onTap: () {
                Navigator.pushNamed(
                  context,
                  '/details',
                  arguments: car,
                );
              },
            ),
          );
        },
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => Navigator.pushNamed(context, '/profile'),
        child: const Icon(Icons.person),
        tooltip: 'Go to Profile',
      ),
    );
  }
}

4. lib/screens/details_screen.dart

 

// lib/screens/details_screen.dart
import 'package:flutter/material.dart';
import '../models/car.dart'; // Import Car model

class DetailsScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final Car car = ModalRoute.of(context)!.settings.arguments as Car;

    return Scaffold(
      appBar: AppBar(title: Text(car.name)),
      body: Center(
        child: SingleChildScrollView(
          padding: const EdgeInsets.all(16.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              ClipRRect(
                borderRadius: BorderRadius.circular(20),
                child: Image.network(
                  car.imageUrl,
                  width: 250,
                  height: 250,
                  fit: BoxFit.cover,
                ),
              ),
              const SizedBox(height: 24),
              Text(
                car.name,
                style: const TextStyle(fontSize: 26, fontWeight: FontWeight.bold),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 12),
              Text(
                car.description,
                style: const TextStyle(fontSize: 16),
                textAlign: TextAlign.center,
              ),
              const SizedBox(height: 40),
              ElevatedButton.icon(
                onPressed: () => Navigator.pop(context),
                icon: const Icon(Icons.arrow_back),
                label: const Text('Back'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

 

5. lib/screens/profile_screen.dart

// lib/screens/profile_screen.dart
import 'package:flutter/material.dart';

class ProfileScreen extends StatelessWidget {
  final String profileImage = 'https://www.shutterstock.com/image-vector/young-smiling-man-avatar-brown-600nw-2261401207.jpg';

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('My Profile')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center, // Center content vertically
          children: [
            CircleAvatar(
              radius: 60,
              backgroundImage: NetworkImage(profileImage),
            ),
            const SizedBox(height: 20),
            const Text(
              'John Doe',
              style: TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
            ),
            Text('john.doe@example.com', style: TextStyle(color: Colors.grey[600])),
            const SizedBox(height: 30),
            ElevatedButton.icon(
              onPressed: () => Navigator.pop(context),
              icon: const Icon(Icons.arrow_back),
              label: const Text('Back to Home'),
            ),
          ],
        ),
      ),
    );
  }
}

 

6. lib/main.dart

 

// lib/main.dart
import 'package:flutter/material.dart';
import 'screens/home_screen.dart';    // Import HomeScreen
import 'screens/details_screen.dart'; // Import DetailsScreen
import 'screens/profile_screen.dart'; // Import ProfileScreen

void main() => runApp(const MyApp()); // Add const for MyApp

class MyApp extends StatelessWidget {
  const MyApp({super.key}); // Add const constructor

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Car List App',
      theme: ThemeData(primarySwatch: Colors.blue),
      initialRoute: '/',
      routes: {
        '/': (context) =>  HomeScreen(),      // Add const to screen widgets
        '/details': (context) =>  DetailsScreen(),
        '/profile': (context) =>  ProfileScreen(),
      },
    );
  }
}

Step 4: Run Your Application

Conclusion

Routing and multi-screen development are essential skills for any Flutter developer. By understanding:

  • Navigator (push & pop)

  • Named routes

  • Data passing between screens

You can build scalable, maintainable, and user-friendly applications.

This foundation will help you create real-world apps like:

  • E-commerce systems

  • Student management apps

  • Dashboard-based applications

 

 

 

 

 

Write A Comment