Popular Searches
Popular Course Categories
Popular Courses

Creating multi-section application navigation

Creating multi-section application navigation

Flutter Navigation & Screens


Creating Multi-Section Application Navigation in Flutter


Multi-section application navigation is the process of organizing a Flutter application into multiple major sections such as Home, Products, Orders, Notifications, Profile, Settings, or Dashboard. Users can switch between these sections using navigation components such as NavigationBar, NavigationRail, NavigationDrawer, or nested navigation flows.


Flutter provides Navigator and Router for screen navigation. For applications with more advanced routing and deep-linking requirements, Flutter documentation recommends using Router-based navigation or a routing package such as go_router. :contentReference[oaicite:0]{index=0}




1. What Is Multi-Section Application Navigation?


A multi-section application divides an application into several top-level areas. Each section represents a major feature of the application.


Example Application Structure



  • Home

  • Products

  • Orders

  • Notifications

  • Profile

  • Settings


For example, an e-commerce application may have:


Home
Products
Cart
Orders
Profile

The user can move between these sections without having to restart the application.




2. Navigation Architecture


A typical multi-section Flutter application can be organized into two navigation levels:



  1. Top-level navigation: Moves between major sections such as Home, Products, Orders, and Profile.

  2. Detail navigation: Opens a specific screen inside a section, such as Product Details or Order Details.


Application
├── Home
│   ├── Featured Products
│   └── Categories
├── Products
│   ├── Product List
│   └── Product Details
├── Orders
│   ├── Order List
│   └── Order Details
└── Profile
    ├── Personal Information
    └── Settings

This structure makes the navigation system easier to understand and maintain.




3. Flutter Navigation Widgets


Flutter provides several Material navigation widgets for different application layouts. The Material widget catalog includes NavigationBar, NavigationDrawer, NavigationRail, and TabBar. :contentReference[oaicite:1]{index=1}










WidgetCommon Use
NavigationBarBottom navigation for primary sections
NavigationRailSide navigation, especially on larger screens
NavigationDrawerDrawer-based navigation
TabBarSwitching between related views or categories
NavigatorStack-based navigation between routes
RouterDeclarative and advanced navigation/deep linking



4. NavigationBar for Multi-Section Applications


NavigationBar is useful when an application has a small number of important top-level destinations. It provides persistent navigation between primary destinations. :contentReference[oaicite:2]{index=2}


Basic Example


import 'package:flutter/material.dart';

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

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const MainScreen(),
    );
  }
}

class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int currentIndex = 0;

  final List<Widget> screens = const [
    HomeScreen(),
    ProductsScreen(),
    OrdersScreen(),
    ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: screens[currentIndex],
      bottomNavigationBar: NavigationBar(
        selectedIndex: currentIndex,
        onDestinationSelected: (index) {
          setState(() {
            currentIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_bag_outlined),
            selectedIcon: Icon(Icons.shopping_bag),
            label: 'Products',
          ),
          NavigationDestination(
            icon: Icon(Icons.receipt_long_outlined),
            selectedIcon: Icon(Icons.receipt_long),
            label: 'Orders',
          ),
          NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}




5. Creating Individual Sections


Each major section should generally be implemented as its own widget.


class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: Text('Welcome to Home'),
      ),
    );
  }
}

class ProductsScreen extends StatelessWidget {
  const ProductsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Products'),
      ),
      body: Center(
        child: Text('Product Section'),
      ),
    );
  }
}

class OrdersScreen extends StatelessWidget {
  const OrdersScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Orders'),
      ),
      body: Center(
        child: Text('Orders Section'),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Profile'),
      ),
      body: Center(
        child: Text('Profile Section'),
      ),
    );
  }
}




6. Understanding selectedIndex


The selectedIndex property determines which navigation destination is currently selected.


int currentIndex = 0;

NavigationBar(
  selectedIndex: currentIndex,
  onDestinationSelected: (index) {
    setState(() {
      currentIndex = index;
    });
  },
)


For example:








IndexSection
0Home
1Products
2Orders
3Profile



7. Why Use a Common Parent Widget?


A common parent widget can control which top-level section is displayed. This keeps the navigation state in one place.


class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int selectedIndex = 0;

  final pages = const [
    HomeScreen(),
    ProductsScreen(),
    OrdersScreen(),
    ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: pages[selectedIndex],
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_bag_outlined),
            selectedIcon: Icon(Icons.shopping_bag),
            label: 'Products',
          ),
          NavigationDestination(
            icon: Icon(Icons.receipt_long_outlined),
            selectedIcon: Icon(Icons.receipt_long),
            label: 'Orders',
          ),
          NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}




8. NavigationBar vs Navigator


These two concepts solve different navigation problems.








NavigationBarNavigator
Switches between major application sectionsPushes and pops routes/screens
Usually remains visibleUsually changes the route stack
Example: Home → OrdersExample: Product List → Product Details
Good for top-level destinationsGood for hierarchical navigation

Flutter's Navigator.push() adds a route to the navigation stack, while Navigator.pop() removes the current route and returns to the previous route. :contentReference[oaicite:3]{index=3}




9. Opening Detail Screens Inside a Section


Suppose the Products section displays a list of products. When the user selects a product, the application can open a Product Details screen.


class ProductsScreen extends StatelessWidget {
  const ProductsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Products'),
      ),
      body: ListView(
        children: [
          ListTile(
            title: const Text('Laptop'),
            subtitle: const Text('₹60,000'),
            trailing: const Icon(Icons.arrow_forward_ios),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const ProductDetailsScreen(
                    productName: 'Laptop',
                    price: 60000,
                  ),
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}


Product Details Screen


class ProductDetailsScreen extends StatelessWidget {
  final String productName;
  final double price;

  const ProductDetailsScreen({
    super.key,
    required this.productName,
    required this.price,
  });

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Product Details'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              productName,
              style: const TextStyle(
                fontSize: 26,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 10),
            Text('Price: ₹$price'),
          ],
        ),
      ),
    );
  }
}




10. Multi-Level Navigation


A real application can contain both top-level and detail-level navigation.


NavigationBar
     |
     +-- Home
     |
     +-- Products
     |      |
     |      +-- Product Details
     |      |       |
     |      |       +-- Reviews
     |      |       +-- Checkout
     |
     +-- Orders
     |      |
     |      +-- Order Details
     |
     +-- Profile
            |
            +-- Edit Profile
            +-- Settings

The bottom navigation controls the major sections, while the Navigator handles screens inside those sections.




11. Preserving Section State with IndexedStack


If every section is rebuilt when the user switches tabs, some temporary UI state may be lost. An IndexedStack can keep multiple section widgets in the widget tree while displaying only the selected one.


class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int selectedIndex = 0;

  final pages = const [
    HomeScreen(),
    ProductsScreen(),
    OrdersScreen(),
    ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: selectedIndex,
        children: pages,
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_bag),
            label: 'Products',
          ),
          NavigationDestination(
            icon: Icon(Icons.receipt),
            label: 'Orders',
          ),
          NavigationDestination(
            icon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}


Advantages of IndexedStack



  • Helps preserve the state of section widgets.

  • Useful for forms, scroll positions, and tab content.

  • Provides smooth switching between sections.

  • Keeps multiple section widgets mounted.




12. NavigationRail for Larger Screens


For tablets, desktop applications, and larger layouts, a side navigation pattern can be more suitable. Flutter provides NavigationRail for persistent navigation on the leading edge of larger screens. :contentReference[oaicite:4]{index=4}


class DesktopNavigation extends StatefulWidget {
  const DesktopNavigation({super.key});

  @override
  State<DesktopNavigation> createState() => _DesktopNavigationState();
}

class _DesktopNavigationState extends State<DesktopNavigation> {
  int selectedIndex = 0;

  final pages = const [
    HomeScreen(),
    ProductsScreen(),
    OrdersScreen(),
    ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Row(
        children: [
          NavigationRail(
            selectedIndex: selectedIndex,
            onDestinationSelected: (index) {
              setState(() {
                selectedIndex = index;
              });
            },
            destinations: const [
              NavigationRailDestination(
                icon: Icon(Icons.home_outlined),
                selectedIcon: Icon(Icons.home),
                label: Text('Home'),
              ),
              NavigationRailDestination(
                icon: Icon(Icons.shopping_bag_outlined),
                selectedIcon: Icon(Icons.shopping_bag),
                label: Text('Products'),
              ),
              NavigationRailDestination(
                icon: Icon(Icons.receipt_long_outlined),
                selectedIcon: Icon(Icons.receipt_long),
                label: Text('Orders'),
              ),
              NavigationRailDestination(
                icon: Icon(Icons.person_outline),
                selectedIcon: Icon(Icons.person),
                label: Text('Profile'),
              ),
            ],
          ),
          const VerticalDivider(width: 1),
          Expanded(
            child: pages[selectedIndex],
          ),
        ],
      ),
    );
  }
}




13. Responsive Multi-Section Navigation


A responsive Flutter application can change its navigation pattern based on available screen width.


LayoutBuilder(
  builder: (context, constraints) {
    if (constraints.maxWidth < 600) {
      return MobileNavigation();
    }

    return DesktopNavigation();
  },
)


A common pattern is:







Screen SizeNavigation Pattern
Small mobileNavigationBar
Large mobile / tabletNavigationBar or NavigationRail
DesktopNavigationRail or NavigationDrawer

Flutter's adaptive navigation examples demonstrate using different navigation patterns depending on screen size, including stack-based navigation on smaller screens and master-detail layouts on larger screens. :contentReference[oaicite:5]{index=5}




14. NavigationDrawer for Multiple Sections


When an application contains many destinations, a drawer can organize navigation options without occupying permanent screen space.


Scaffold(
  appBar: AppBar(
    title: const Text('My Application'),
  ),
  drawer: NavigationDrawer(
    children: [
      const Padding(
        padding: EdgeInsets.all(16),
        child: Text(
          'Application Menu',
          style: TextStyle(
            fontSize: 20,
            fontWeight: FontWeight.bold,
          ),
        ),
      ),
      NavigationDrawerDestination(
        icon: const Icon(Icons.home),
        label: const Text('Home'),
      ),
      NavigationDrawerDestination(
        icon: const Icon(Icons.shopping_bag),
        label: const Text('Products'),
      ),
      NavigationDrawerDestination(
        icon: const Icon(Icons.receipt),
        label: const Text('Orders'),
      ),
      NavigationDrawerDestination(
        icon: const Icon(Icons.settings),
        label: const Text('Settings'),
      ),
    ],
  ),
  body: const Center(
    child: Text('Application Content'),
  ),
)



15. Passing Data Between Sections


Data can be passed to a detail screen through its constructor.


class Product {
  final String name;
  final double price;

  const Product({
    required this.name,
    required this.price,
  });
}

final product = Product(
  name: 'Smartphone',
  price: 25000,
);

Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => ProductDetailsScreen(
      productName: product.name,
      price: product.price,
    ),
  ),
);


This approach makes the destination screen explicitly receive the data it needs.




16. Returning Data from a Detail Screen


A detail screen can return information to its previous screen using Navigator.pop().


final result = await Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) => const SelectionScreen(),
  ),
);

if (!context.mounted) return;

if (result != null) {
  print(result);
}


The destination screen can return the result:


Navigator.pop(context, 'Selected Product');



17. Nested Navigation


Complex applications may require a separate navigation stack inside a particular section. This is called nested navigation.


For example:


Application Navigator

├── Home
├── Products
├── Orders
└── Profile
       │
       ├── Profile Overview
       ├── Edit Profile
       ├── Addresses
       └── Account Settings

A nested Navigator can manage the routes inside the Profile section without putting every profile route into the application's top-level navigation stack. Flutter's official nested-navigation recipe demonstrates this pattern for multi-page flows. :contentReference[oaicite:6]{index=6}




18. Example of a Nested Navigator


class ProfileFlow extends StatefulWidget {
  const ProfileFlow({super.key});

  @override
  State<ProfileFlow> createState() => _ProfileFlowState();
}

class _ProfileFlowState extends State<ProfileFlow> {
  final navigatorKey = GlobalKey<NavigatorState>();

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      onGenerateRoute: (settings) {
        return MaterialPageRoute(
          builder: (context) => const ProfileHome(),
        );
      },
    );
  }
}

class ProfileHome extends StatelessWidget {
  const ProfileHome({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Profile'),
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => const EditProfileScreen(),
              ),
            );
          },
          child: const Text('Edit Profile'),
        ),
      ),
    );
  }
}

class EditProfileScreen extends StatelessWidget {
  const EditProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Edit Profile'),
      ),
      body: const Center(
        child: Text('Edit Profile'),
      ),
    );
  }
}




19. Using go_router for Larger Applications


For applications with complex navigation, multiple navigators, and deep linking requirements, a routing package such as go_router can simplify route configuration. Flutter's navigation documentation specifically identifies go_router as a routing option for advanced requirements. :contentReference[oaicite:7]{index=7}


Installation


flutter pub add go_router

Basic Router Configuration


import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';

final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const HomeScreen(),
    ),
    GoRoute(
      path: '/products',
      builder: (context, state) => const ProductsScreen(),
    ),
    GoRoute(
      path: '/orders',
      builder: (context, state) => const OrdersScreen(),
    ),
    GoRoute(
      path: '/profile',
      builder: (context, state) => const ProfileScreen(),
    ),
  ],
);

void main() {
  runApp(
    MaterialApp.router(
      routerConfig: router,
    ),
  );
}


Navigating with go_router


context.go('/products');

For example:


ElevatedButton(
  onPressed: () {
    context.go('/products');
  },
  child: const Text('Open Products'),
)



20. Multi-Section Navigation with go_router


A larger application can define a route hierarchy.


/
├── /home
├── /products
│   └── /products/:id
├── /orders
│   └── /orders/:id
└── /profile
    ├── /profile/edit
    └── /profile/settings

For example:


final router = GoRouter(
  routes: [
    GoRoute(
      path: '/',
      builder: (context, state) => const MainScreen(),
      routes: [
        GoRoute(
          path: 'products',
          builder: (context, state) => const ProductsScreen(),
        ),
        GoRoute(
          path: 'orders',
          builder: (context, state) => const OrdersScreen(),
        ),
        GoRoute(
          path: 'profile',
          builder: (context, state) => const ProfileScreen(),
        ),
      ],
    ),
  ],
);



21. Deep Linking in Multi-Section Applications


Deep linking allows a URL or external link to open a specific location inside an application. Flutter supports deep linking on Android, iOS, and web. :contentReference[oaicite:8]{index=8}


For example:


https://example.com/products
https://example.com/products/101
https://example.com/orders/500
https://example.com/profile

A deep link such as:


/products/101

can take the user directly to Product 101 instead of requiring them to manually open Products first.




22. Route Parameters


Dynamic route parameters can identify a specific resource.


GoRoute(
  path: '/products/:id',
  builder: (context, state) {
    final productId = state.pathParameters['id'];

    return ProductDetailsScreen(
      productId: productId!,
    );
  },
)


For example:


/products/101

Here, 101 becomes the product ID.




23. Multi-Section E-Commerce Example


The following example demonstrates a basic e-commerce navigation structure.


import 'package:flutter/material.dart';

void main() {
  runApp(const ECommerceApp());
}

class ECommerceApp extends StatelessWidget {
  const ECommerceApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue,
        ),
        useMaterial3: true,
      ),
      home: const MainScreen(),
    );
  }
}

class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int selectedIndex = 0;

  final pages = const [
    HomeScreen(),
    ProductsScreen(),
    CartScreen(),
    ProfileScreen(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: selectedIndex,
        children: pages,
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_bag_outlined),
            selectedIcon: Icon(Icons.shopping_bag),
            label: 'Products',
          ),
          NavigationDestination(
            icon: Icon(Icons.shopping_cart_outlined),
            selectedIcon: Icon(Icons.shopping_cart),
            label: 'Cart',
          ),
          NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}

class HomeScreen extends StatelessWidget {
  const HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: Text('Welcome to our store'),
      ),
    );
  }
}

class ProductsScreen extends StatelessWidget {
  const ProductsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Products'),
      ),
      body: ListView(
        children: [
          ListTile(
            leading: const Icon(Icons.phone_android),
            title: const Text('Smartphone'),
            subtitle: const Text('₹25,000'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      const ProductDetailsScreen(),
                ),
              );
            },
          ),
          ListTile(
            leading: const Icon(Icons.laptop),
            title: const Text('Laptop'),
            subtitle: const Text('₹60,000'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) =>
                      const ProductDetailsScreen(),
                ),
              );
            },
          ),
        ],
      ),
    );
  }
}

class ProductDetailsScreen extends StatelessWidget {
  const ProductDetailsScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Product Details'),
      ),
      body: const Center(
        child: Text('Product Details'),
      ),
    );
  }
}

class CartScreen extends StatelessWidget {
  const CartScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Cart'),
      ),
      body: Center(
        child: Text('Your Cart'),
      ),
    );
  }
}

class ProfileScreen extends StatelessWidget {
  const ProfileScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Profile'),
      ),
      body: Center(
        child: Text('User Profile'),
      ),
    );
  }
}




24. Navigation Flow of the E-Commerce Application


MainScreen

├── Home

├── Products
│   ├── Smartphone
│   │   └── Product Details
│   └── Laptop
│       └── Product Details

├── Cart

└── Profile
    ├── Edit Profile
    └── Settings

Here, NavigationBar controls the four primary sections, while Navigator.push() handles product detail screens.




25. Keeping Navigation Code Organized


Large applications should avoid placing all navigation code inside one huge widget.


A possible project structure is:


lib/
├── main.dart
├── navigation/
│   ├── app_navigation.dart
│   └── app_routes.dart
├── screens/
│   ├── home/
│   │   └── home_screen.dart
│   ├── products/
│   │   ├── products_screen.dart
│   │   └── product_details_screen.dart
│   ├── orders/
│   │   ├── orders_screen.dart
│   │   └── order_details_screen.dart
│   └── profile/
│       ├── profile_screen.dart
│       └── settings_screen.dart
├── widgets/
│   └── app_navigation_bar.dart
└── models/
    └── product.dart



26. Creating a Reusable NavigationBar Widget


Navigation UI can be extracted into a reusable widget.


class AppNavigationBar extends StatelessWidget {
  final int selectedIndex;
  final ValueChanged<int> onDestinationSelected;

  const AppNavigationBar({
    super.key,
    required this.selectedIndex,
    required this.onDestinationSelected,
  });

  @override
  Widget build(BuildContext context) {
    return NavigationBar(
      selectedIndex: selectedIndex,
      onDestinationSelected: onDestinationSelected,
      destinations: const [
        NavigationDestination(
          icon: Icon(Icons.home_outlined),
          selectedIcon: Icon(Icons.home),
          label: 'Home',
        ),
        NavigationDestination(
          icon: Icon(Icons.search_outlined),
          selectedIcon: Icon(Icons.search),
          label: 'Search',
        ),
        NavigationDestination(
          icon: Icon(Icons.person_outline),
          selectedIcon: Icon(Icons.person),
          label: 'Profile',
        ),
      ],
    );
  }
}


It can then be used inside the main screen:


bottomNavigationBar: AppNavigationBar(
  selectedIndex: selectedIndex,
  onDestinationSelected: (index) {
    setState(() {
      selectedIndex = index;
    });
  },
),



27. Navigation State Management


As an application grows, navigation state may need to interact with application state.


Examples include:



  • Logged-in or logged-out state.

  • Selected user account.

  • Shopping cart count.

  • Unread notification count.

  • Selected product.

  • Current order.

  • Application settings.


For simple applications, local setState() may be sufficient. Larger applications may use state-management solutions such as Provider, Riverpod, Bloc, or another architecture appropriate to the project.




28. Example: Navigation with Cart Count


class MainScreen extends StatefulWidget {
  const MainScreen({super.key});

  @override
  State<MainScreen> createState() => _MainScreenState();
}

class _MainScreenState extends State<MainScreen> {
  int selectedIndex = 0;
  int cartCount = 2;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: const HomeScreen(),
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: [
          const NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Badge(
              label: Text('$cartCount'),
              child: const Icon(Icons.shopping_cart_outlined),
            ),
            selectedIcon: Badge(
              label: Text('$cartCount'),
              child: const Icon(Icons.shopping_cart),
            ),
            label: 'Cart',
          ),
          const NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}




29. Authentication and Navigation


Many applications have public and authenticated sections.


Application

├── Login
├── Register

└── Authenticated Area
    ├── Home
    ├── Products
    ├── Orders
    └── Profile

After successful login, the application can navigate to the main authenticated section.


Navigator.pushReplacement(
  context,
  MaterialPageRoute(
    builder: (context) => const MainScreen(),
  ),
);

pushReplacement() is useful when the previous screen should not remain as the next back-navigation destination.




30. Logout Navigation


When a user logs out, an application commonly clears or changes the authenticated navigation state and takes the user to the login screen.


Navigator.pushAndRemoveUntil(
  context,
  MaterialPageRoute(
    builder: (context) => const LoginScreen(),
  ),
  (route) => false,
);

This removes the previous routes from the navigation stack.




31. Avoiding Too Many Top-Level Sections


Top-level navigation should contain the application's major destinations rather than every individual screen.


For example, instead of:


Home
Product 1
Product 2
Product 3
Product 4
Order 1
Order 2
Settings
Edit Profile

Use:


Home
Products
Orders
Profile
Settings

Then navigate to details from inside each section.




32. Navigation and Deep Links


When an application supports deep links, a URL can represent a specific application location.


/products
/products/101
/orders
/orders/500
/profile/settings

This is especially useful for web applications, product sharing, notification links, marketing links, and external navigation. Flutter supports deep linking across Android, iOS, and web. :contentReference[oaicite:9]{index=9}




33. Named Routes


Flutter supports named routes, but the current Flutter navigation documentation states that named routes are not recommended for most new applications. For new applications, Flutter recommends considering go_router or using Navigator with MaterialPageRoute. :contentReference[oaicite:10]{index=10}


A basic named-route example for understanding existing projects is:


MaterialApp(
  routes: {
    '/': (context) => const HomeScreen(),
    '/products': (context) => const ProductsScreen(),
    '/orders': (context) => const OrdersScreen(),
    '/profile': (context) => const ProfileScreen(),
  },
)

Navigation:


Navigator.pushNamed(context, '/products');



34. Common Navigation Mistakes


Mistake 1: Putting Every Screen in Bottom Navigation


Bottom navigation should generally represent major application sections rather than every detail page.


Mistake 2: Losing Tab State


If a section contains forms or scrollable content, repeatedly rebuilding it can cause unwanted state changes. Consider appropriate state preservation techniques such as IndexedStack.


Mistake 3: Huge Navigation Files


Move route definitions and navigation components into separate files as the application grows.


Mistake 4: Mixing Navigation and Business Logic


Keep authentication, database, API, and business logic separate from navigation UI when possible.


Mistake 5: Ignoring Responsive Layouts


A bottom navigation layout designed for a phone may not be appropriate for a desktop screen. Consider adaptive navigation patterns.


Mistake 6: Using the Wrong Navigation Level


Use top-level navigation for major sections and stack navigation for details and temporary flows.




35. Best Practices



  • Keep top-level destinations focused on major application sections.

  • Use NavigationBar for bottom-oriented primary navigation.

  • Use NavigationRail or NavigationDrawer when appropriate for larger screens.

  • Use Navigator.push() for hierarchical detail screens.

  • Use Navigator.pop() to return from a pushed route.

  • Use IndexedStack when preserving multiple section states is useful.

  • Separate navigation configuration from business logic.

  • Use nested navigation for self-contained multi-step flows.

  • Consider go_router for complex routing and deep linking.

  • Test navigation on different screen sizes.

  • Provide meaningful labels and icons for navigation destinations.

  • Keep back navigation predictable.




36. Complete Navigation Flow


User Opens App
       |
       v
   Home Section
       |
       +----------------+
       |                |
       v                v
  Products           Profile
       |
       v
Product Details
       |
       v
Add to Cart
       |
       v
     Cart
       |
       v
    Checkout
       |
       v
     Orders



37. Practical Project Example


Consider building a learning application with the following sections:


Learning App
├── Home
├── Courses
├── My Learning
├── Notifications
└── Profile

Inside Courses:


Courses
├── Flutter
├── Dart
├── Java
└── Web Development

When the user taps Flutter:


Courses
   |
   +-- Flutter Course
          |
          +-- Course Details
          +-- Lessons
          +-- Progress
          +-- Certificate

This demonstrates how top-level navigation and hierarchical navigation can work together.




38. Mini Project: Learning App Navigation


import 'package:flutter/material.dart';

void main() {
  runApp(const LearningApp());
}

class LearningApp extends StatelessWidget {
  const LearningApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: const LearningHome(),
    );
  }
}

class LearningHome extends StatefulWidget {
  const LearningHome({super.key});

  @override
  State<LearningHome> createState() => _LearningHomeState();
}

class _LearningHomeState extends State<LearningHome> {
  int selectedIndex = 0;

  final pages = const [
    HomePage(),
    CoursesPage(),
    LearningPage(),
    ProfilePage(),
  ];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: IndexedStack(
        index: selectedIndex,
        children: pages,
      ),
      bottomNavigationBar: NavigationBar(
        selectedIndex: selectedIndex,
        onDestinationSelected: (index) {
          setState(() {
            selectedIndex = index;
          });
        },
        destinations: const [
          NavigationDestination(
            icon: Icon(Icons.home_outlined),
            selectedIcon: Icon(Icons.home),
            label: 'Home',
          ),
          NavigationDestination(
            icon: Icon(Icons.school_outlined),
            selectedIcon: Icon(Icons.school),
            label: 'Courses',
          ),
          NavigationDestination(
            icon: Icon(Icons.play_circle_outline),
            selectedIcon: Icon(Icons.play_circle),
            label: 'Learning',
          ),
          NavigationDestination(
            icon: Icon(Icons.person_outline),
            selectedIcon: Icon(Icons.person),
            label: 'Profile',
          ),
        ],
      ),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Home'),
      ),
      body: Center(
        child: Text('Welcome to Learning App'),
      ),
    );
  }
}

class CoursesPage extends StatelessWidget {
  const CoursesPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Courses'),
      ),
      body: ListView(
        children: [
          ListTile(
            leading: const Icon(Icons.flutter_dash),
            title: const Text('Flutter Training'),
            subtitle: const Text('Learn Flutter Development'),
            onTap: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const CourseDetailsPage(),
                ),
              );
            },
          ),
          const ListTile(
            leading: Icon(Icons.code),
            title: Text('Dart Programming'),
            subtitle: Text('Learn Dart Programming'),
          ),
        ],
      ),
    );
  }
}

class CourseDetailsPage extends StatelessWidget {
  const CourseDetailsPage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Flutter Training'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              'Flutter Training Course',
              style: TextStyle(
                fontSize: 24,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            const Text(
              'Learn Flutter, Dart, widgets, navigation, state management and application development.',
            ),
            const SizedBox(height: 20),
            ElevatedButton(
              onPressed: () {
                Navigator.pop(context);
              },
              child: const Text('Back'),
            ),
          ],
        ),
      ),
    );
  }
}

class LearningPage extends StatelessWidget {
  const LearningPage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('My Learning'),
      ),
      body: Center(
        child: Text('Continue Learning'),
      ),
    );
  }
}

class ProfilePage extends StatelessWidget {
  const ProfilePage({super.key});

  @override
  Widget build(BuildContext context) {
    return const Scaffold(
      appBar: AppBar(
        title: Text('Profile'),
      ),
      body: Center(
        child: Text('User Profile'),
      ),
    );
  }
}




39. Learning Outcomes


After completing this topic, you should be able to:



  • Understand multi-section application navigation.

  • Create top-level navigation using NavigationBar.

  • Manage navigation state with selectedIndex.

  • Create independent screens for application sections.

  • Navigate from a section to a detail screen.

  • Pass information between screens.

  • Return information from a detail screen.

  • Preserve section state using IndexedStack.

  • Build responsive navigation using NavigationRail.

  • Understand NavigationDrawer-based navigation.

  • Understand nested navigation.

  • Understand deep linking.

  • Understand the role of Navigator and Router.

  • Use routing packages such as go_router for complex applications.

  • Organize navigation code in a scalable project structure.




40. Interview Questions


Q1. What is multi-section navigation?


Multi-section navigation organizes an application into major areas such as Home, Products, Orders, and Profile and allows users to switch between those areas.


Q2. What is NavigationBar used for?


NavigationBar is used for persistent navigation between primary destinations, commonly at the bottom of a Material application.


Q3. What does selectedIndex do?


It identifies the currently selected navigation destination.


Q4. What does Navigator.push() do?


It adds a new route to the Navigator's route stack.


Q5. What does Navigator.pop() do?


It removes the current route and returns to the previous route.


Q6. Why use IndexedStack?


It allows multiple child sections to remain mounted while displaying one selected child, which can help preserve section state.


Q7. What is nested navigation?


Nested navigation means using a separate Navigator for a subsection or self-contained flow inside a larger application.


Q8. What is deep linking?


Deep linking allows an external URL or URI to open a specific location inside an application.


Q9. When can NavigationRail be useful?


It is useful for persistent side-oriented navigation, particularly in tablet and desktop layouts.


Q10. What is go_router?


go_router is a Flutter-maintained routing package that provides a declarative API for navigation and supports complex routing scenarios such as nested routes and deep links. :contentReference[oaicite:11]{index=11}




41. Practice Exercises



  1. Create a Flutter application with Home, Search, Cart, and Profile sections.

  2. Use NavigationBar to switch between all sections.

  3. Use IndexedStack to preserve section state.

  4. Create a Product List screen inside the Products section.

  5. Navigate from Product List to Product Details.

  6. Pass product name and price to Product Details.

  7. Return a selected value from Product Details.

  8. Create a Profile section with a nested Settings screen.

  9. Implement a responsive NavigationBar/NavigationRail layout.

  10. Convert the application to use go_router.

  11. Add a dynamic product route such as /products/:id.

  12. Test a deep link that opens a specific product.




42. Quick Revision















ConceptPurpose
NavigationBarPrimary bottom navigation
NavigationRailSide navigation for larger layouts
NavigationDrawerDrawer-based application navigation
NavigatorStack-based route navigation
Navigator.push()Adds a route
Navigator.pop()Removes the current route
IndexedStackHelps preserve multiple section widgets
Nested NavigatorManages navigation inside a subsection
RouterDeclarative and advanced navigation
go_routerRouting package for complex navigation
Deep LinkingOpens a specific application location from a URL/URI



43. Key Takeaways



  • Multi-section navigation divides an application into clear top-level destinations.

  • NavigationBar is useful for bottom-oriented primary navigation.

  • NavigationRail and NavigationDrawer provide alternative navigation layouts.

  • Navigator handles route-stack navigation between screens.

  • NavigationBar and Navigator can be used together.

  • IndexedStack can help preserve the state of multiple sections.

  • Nested navigators are useful for self-contained navigation flows.

  • Responsive applications can change navigation patterns based on available screen size.

  • Deep linking allows users to open specific application locations directly.

  • For advanced routing requirements, Flutter supports Router-based navigation and routing packages such as go_router. :contentReference[oaicite:12]{index=12}




44. Useful Resources


Official Flutter Navigation Documentation: Flutter Navigation and Routing


Flutter Navigation Cookbook: Flutter Navigation Cookbook


Flutter Deep Linking: Flutter Deep Linking Documentation


Flutter Material Components: Flutter Material Widgets


JustAcademy Flutter Training: JustAcademy Flutter Training Course


Register for Course Demo: Register for Flutter Course Demo


whatsapp